读书人

函数指针与构造体

发布时间: 2012-12-22 12:05:06 作者: rapoo

函数指针与结构体
在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++中对于虚函数的调用就非常类似了。




读书人网 >编程

热点推荐