我是C的初学者,我无法理解为什么C使用虚拟表来实现多态而不是简单的函数指针.
我们来看一个例子:
struct Shape {
virtual double area() = 0;
};
struct Square: public Shape {
virtual double area();
/* ... */
};
struct Circle: public Shape {
virtual double area();
/* ... */
};
double f(Shape &s) { return 42.0 + s.area(); }
C通常(总是?)如何实现多态:Shape和每个派生类都有一个指向虚拟表的隐藏指针作为第一个元素.当调用s.area()时,指向相应区域函数的指针取自s的虚拟表.
但是如果我不了解C和虚拟表并希望在C中实现这样的多态性,我会这样做:
struct Shape {
double (*area)(struct Shape *this);
};
struct Square { /* is a Shape */
double (*area)(struct Square *this);
/* ... */
};
struct Circle { /* is a Shape */
double (*area)(struct Circle *this);
/* ... */
};
double f(struct Shape *s) { return 42.0 + s->area(s); }
double cirlce_area(struct Circle *this);
double square_area(struct Square *this);
/* ... */
struct Circle c = { &circle_area, ... };
printf("%f", f((struct Shape *)c));
当调用s-> area()时,使用来自s结构的第一个指针.
为什么C使用虚拟表而不是仅仅在结构的开头放置指向虚函数的指针(具有相同的顺序)?我目前无法找到任何理由为什么最后一种方法可能无效.
解决方法:
从概念上讲,这是完全相同的事情.
虚方法表不是函数指针列表.它没有集成在对象本身中,因为它对于对象的类是静态的,因此它可以在同一个类的实例之间共享(在对象整个生命周期中保存初始化期间的计算能力和内存).
具体来说,在C中,每个构造函数都将虚方法表指针设置为它所属的类的指针.因此,在最外层构造函数运行之后,虚方法将解析为该对象所在的类.