【发布时间】:2014-04-12 12:46:50
【问题描述】:
我是 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的虚表中取出对应area函数的指针。
但是如果我不了解 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++ 标准不要求使用指向虚拟表的指针 - 实现也可以使用哈希表,或将函数指针直接放入对象中,就像您刚才所做的那样。
-
当你有很多这样的函数指针时,即使在 C 语言中,你也会把它们都放在一个不同的结构中,只保留一个指向它的指针。这实际上在 Linux 内核中是非常惯用的。
-
不只是 Linux 内核,Microsoft COM 也是如此。但考虑到 Linux 不喜欢 C++,我想 Linux 使用如此常见的 C++ 模式更令人惊讶。
标签: c++ polymorphism virtual-functions