以下代码中将创建多少个V表?

时间:2011-08-24 10:12:03

标签: c++

class base{
public:
    virtual void fn() {

    }
};

class der1 : public base {
    void fn() {

    }
};

class der2 : public der1 {
    virtual void fn() {

    }
};

我有另一个问题。在类der1的定义中,我没有在重新定义函数fn时提到“虚拟”。创建V表时有什么效果

4 个答案:

答案 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前缀代表typeinfotypeinfo namevtable

答案 2 :(得分:2)

对此没有具体的答案,因为虚拟主义被排除在编译器的实现细节之外 C ++标准根本不讨论vptrvtable。对此的答案因编译器而异。

答案 3 :(得分:1)

  

以下代码中将创建多少个V表?

这个问题无法回答 你也不想知道,也不关心。它对您的代码的使用或工作方式没有任何影响。

  

我有另一个问题。

好听。

  

在类der1的定义中,我没有在重新定义函数fn时提到“虚拟”。

因为'void fn()'的定义与基类完全相同,所以它继承了它所覆盖的函数的虚拟属性。因此它也是虚拟的。

  

创建V表时是否有任何影响

没有办法说出来。由于V-Table与C ++语言无关(它们是编译器在代码背后所做的,如果它甚至使用V表(它可能不是))。