class base{
public:
virtual void fn() {
}
};
class der1 : public base {
void fn() {
}
};
class der2 : public der1 {
virtual void fn() {
}
};
我有另一个问题。在类der1的定义中,我没有在重新定义函数fn时提到“虚拟”。创建V表时有什么效果
答案 0 :(得分:3)
如前所述,vtable是特定于编译器/平台的实现细节,因此没有一般性的答案。
我有另一个问题。在类der1的定义中,我没有在重新定义函数fn时提到“虚拟”。创建V表时有什么效果
由于函数fn()
已在基类中定义为virtual
,因此所有子类实现也是按定义虚拟的(从而覆盖基类实现),无论它们是否显式声明如此。所以vtable将包含它们(如果特定的编译器生成一个)。
您可以通过使base::fn()
纯虚拟来轻松测试。如果声明der1::fn()
虚拟有所不同,则无法在没有它的情况下实例化der1
。
答案 1 :(得分:3)
所以,正如迂腐的答案所暗示的那样:C ++语言没有提到v-tables,它是所有主要编译器使用的实现细节,因为它相对简单且非常高效(因为它如此使用,优化是众所周知的)
话虽如此,典型的答案是每个类都有一个包含虚函数的v表。如果被证明是未使用的,有些可能会被优化。
通常,可能没有必要为抽象类生成v表,因为它无法实例化。但是仍然允许在构造函数和析构函数中调用虚函数(虽然效果并不总是那些预期的),因此编译器通常会生成一个v表,只需将纯虚函数的条目设置为null。
因此,你的答案可能是 3 。
以下表示GCC等编译器实现Itanium C++ ABI。
您可以通过生成库并转储符号来实际验证此3
(为具有虚函数的类生成v-tables和typeinfo符号):
$ nm somelib.so | grep Foo
00000000012a48b0 V _ZTIN3FooE
0000000000e0fca0 V _ZTSN3FooE
00000000012a4620 V _ZTVN3FooE
$ nm somelib.so | grep Foo | c++filt
00000000012a48b0 V typeinfo for Foo
0000000000e0fca0 V typeinfo name for Foo
00000000012a4620 V vtable for Foo
要查找的_ZTIN
,_ZTSN
和_ZTVN
前缀代表typeinfo
,typeinfo name
和vtable
。
答案 2 :(得分:2)
对此没有具体的答案,因为虚拟主义被排除在编译器的实现细节之外
C ++标准根本不讨论vptr
或vtable
。对此的答案因编译器而异。
答案 3 :(得分:1)
以下代码中将创建多少个V表?
这个问题无法回答 你也不想知道,也不关心。它对您的代码的使用或工作方式没有任何影响。
我有另一个问题。
好听。
在类der1的定义中,我没有在重新定义函数fn时提到“虚拟”。
因为'void fn()'的定义与基类完全相同,所以它继承了它所覆盖的函数的虚拟属性。因此它也是虚拟的。
创建V表时是否有任何影响
没有办法说出来。由于V-Table与C ++语言无关(它们是编译器在代码背后所做的,如果它甚至使用V表(它可能不是))。