C++ 在菱形继承中为哪个类创建了虚拟表?

C++ 在菱形继承中为哪个类创建了虚拟表?,c++,C++,考虑以下代码段: class A { }; class B:public virtual A { }; class C:public virtual A { }; class D:public B,public C { }; int main() { cout<<sizeof(A)<<" "<<sizeof(B)<<" "<<sizeof(C)<<" "<<sizeof(D)); retu

考虑以下代码段:

class A
{
};

class B:public virtual A
{
};

class C:public virtual A
{
};

class D:public B,public C
{
};

int main()
{
    cout<<sizeof(A)<<" "<<sizeof(B)<<" "<<sizeof(C)<<" "<<sizeof(D));
    return 0;
}
由于创建了
vptr
,类
B
C
的大小为4字节。这是否意味着为类
B
C
创建了
虚拟表
?那
A

一般来说,编译器会为哪些类在diamond继承中准确地创建
虚拟表?
创建虚拟表的决定是否特定于编译器?


请结合上述示例或其他更好的示例进行回答。

是的,具有虚拟基的类需要某种类型的vtable或等效的vtable。您需要一些机制来在运行时查找实际的基本子对象!(请记住,虚拟基子对象是最派生的对象的责任,而不是直接继承的对象的责任。)

如果编译器生成VTABLES,他将为任何需要VTABLES的类(包含虚拟函数,…)生成VTABLES

A不需要VTABLE=>size==1[最小大小]

B需要一个=>size==4[您使用的是32位…]

C也需要一个=>size==4


D也需要一个=>size==8(两个条目,每个VTABLE D引用一个)

将为B、C和D创建虚拟表。虽然B和C各有一个vptr,但D将有两个vptr。一个指向VTable的B部分,另一个指向VTable的C部分


注意:VTable不是强制性的,只要继承关系可以正确建模,编译器就可以提供自己的实现。(但是大多数编译器都实现VTables)

没有任何规定编译器必须为任何类创建
vptr
。也就是说,在现实生活中,编译器确实会生成
vptr
s,原因有两个:

  • 虚拟调度(显而易见)
  • RTTI,例如,根据
    动态\u cast
    的要求(不太明显)
  • 通常,类的
    vtable
    中的条目将指向某种“类型信息”结构,该结构为RTTI提供足够的信息


    正是这些信息使编译器能够计算出,如果您将
    B*
    C*
    D*
    转换为
    A*
    ,那么对于
    B
    C
    A
    vptr
    ,需要执行哪些操作
    D
    只是简单地将两者聚合起来。

    即使是
    virtual
    函数解析的实现也是特定于编译器的。不需要有
    虚拟表
    ,但很可能会有。您应该指定编译器。具体来说,我使用的是ideone(gcc-4.3.4)。
    更有效的C++
    对此有一些详细说明<代码>第24项:了解虚拟函数、多重继承、虚拟基类和RTTI的成本
    。我没有时间全部看一遍,但这表明可能只需要3个VPTR,其中一个可以共享。(当然,这并不意味着任何实现都要遵循他所说的)。
    1 4 4 8