函数指针与结构体

在C++中,面向对象是通过虚函数来实现的,仅有虚函数,当然只是一个面向对象的皮毛,因为实际上真正的面向对象概念消息和消息响应。先撇开目前市面上面向对象中关于封装变化,依赖倒转等一些概念性和理论性的东西。我们在这边,仅考虑C++中虚函数在C中的模拟实现,以便于更好的理解虚函数。

假定我们现在有一个函数的原形如下

int print_char(int c);


在C语言中,可以通过typedef方式定义一个函数的原形指针:

typedef int (*lpfnPrint)(int c);


函数原形的指针形式定义了更一般的函数方式。在C++中class或者struct是包含数据和操作(函数)的集合,class只是默认是私有的struct的实现。在C语言中,只有struct类型,因此不存在public和private的语法说明。在C语言中,struct是一个数据类型的集合,如果我们把函数指针也看作是一个数据(本来这个就是一个数据,指向某个函数的数据,同时也是一个操作),那么在C语言中的struct也就可以包含数据和操作。

struct BaseClass
{
lpfnPrint lpfn_print;
}


实现print函数
int print_char(int c)
{
printf("%c", c);
return 0;
}

int print_int(int c)
{
printf("%d", c);
return 0;
}


于是,我们可以定义一个结构体的变量

BaseClass b;
b.lpfn_print = print_char;

此时,我们就可以用b.lpfn_print(97)输出字符a了。

当我们修改打印函数为
b.lpfn_print = print_int

再次调用b.lpfn_print(97);就可以输出整数97。

这个是在运行时进行函数的绑定,与C++中编译器中的虚函数编译时绑定还是有一些差别的。

上面的实现,已经有些虚函数的概念,但与现在的C++中的虚函数还是有一个差别。要想得到类似C++的虚函数,就得了解C++中对于虚函数的实现,一般而言,C++的虚函数是通过虚函数表实现的,虚函数表是一个数组,索引代表一个函数指针,实现了具体函数的调用。因此,我们可以定义一个只包含函数指针的结构体类型来表示虚函数,我们命之为VirtualTable。

struct VirtualTable
{
lpfnPrint print_func;
};


然后我们再定义下面的结构体

struct Base
{
struct VirtualTable v;
};

struct Device
{
struct Base b;
};

上面的Device和Base具有相同的结构体内存类型,只是包含了不同的名字,因此我们可以在main函数进行如下的调用:


int main()
{
struct Base b = { print_char }; // 本来编译做的事情,现在由我们手工做了。
struct Device d = { print_int };

// 定义结构体指针
struct Base *p = NULL;

p = &b;
p->v.print_func(97);

p = &d; // 和C++中从基类中派生后的函数类似
p->v.print_func(97);

return 0;
}



p->v.print_func,与C++中对于虚函数的调用就非常类似了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值