所有类都有编译器为它们创建的Vtable吗?

时间:2011-04-18 23:12:13

标签: c++ vtable

网上有很多关于VTables的资源。他们通常对此有相同的陈述:

每当类本身包含虚函数或覆盖父类的虚函数时,编译器就为该类构建一个vtable。这意味着并非所有类都有编译器为它们创建的vtable。 vtable包含指向该类中虚函数的函数指针。每个类只能有一个vtable,同一个类的所有对象将共享相同的vtable。

那么为什么这意味着并非所有类都有编译器为它们创建的vtable?是因为somc类没有虚函数吗?

3 个答案:

答案 0 :(得分:7)

正。有些类没有vtable,因为它们没有任何虚拟方法。

虚方法是编译器无法生成直接调用的方法,因为它根据类的实现而有所不同。 Vtables是一种查找表,可以通过延迟在程序运行期间调用哪个实现的决定来解决这个问题:编译器生成方法查找而不是生成函数调用,然后调用返回的方法

举个例子:

class Foo
{
public:
    virtual void vMethod()
    {
        std::cout << "Foo::vMethod was called!" << std::endl;
    }
};

class Bar : public Foo
{
public:
    virtual void vMethod()
    {
        std::cout << "Bar::vMethod was called!" << std::endl;
        std::cout << "This is not the same as Foo::vMethod." << std::endl;
    }
};

Foo* foo = new Bar;
foo->vMethod();

这将打印Bar的消息。在大多数非平凡的场景中,编译器无法事先知道调用虚方法的对象的类型。如上所述,vtable通过提供统一的查找机制来查找方法实现来解决问题,无论对象的类型如何。

vtable指针必须存在于类的每个实例中(这需要额外内存指针的大小,可能是4或8个字节),以及程序地址空间中某些不重要的静态内存。这对你来说似乎并不是很多(事实上很多人会同意),但在某些情况下(例如内存非常受限的嵌入式系统),这可能很麻烦。拥有每个类的vtable会违反一般的C ++原则,你只需要为你使用的东西付费,因此编译器不会生成任何vtable,如果不需要的话。

没有vtable具有显着的副作用,即禁用 r un t ime t ype i 信息。如果您需要在代码中使用 RTTI ,则您的类必须至少具有一个虚拟方法。惯例是在这些情况下将析构函数标记为虚拟。

答案 1 :(得分:5)

实际上,C ++中没有任何内容要求任何类都有vtable - 这完全是一个实现问题。但是,具有虚函数的类必须以某种方式支持多态函数调用,并且这将始终需要某种类型的表/映射。此表/映射将由编译器为具有多态函数的类创建,并且可能(根据编译器质量)为不具有多态函数的类创建。

答案 2 :(得分:2)

此外,某些类没有vtable,因为已明确删除,请参阅__declspec(novtable)(特定于编译器)