2

我想知道 C++ 中成员变量和 vtable 指针在菱形虚拟继承上的顺序。

考虑以下继承:

class Base
{
    int b;
};

class Derived: public virtual Base
{
    int d;
};

class Derived2: public virtual Base
{
    int d2;
};

class Derived3: public Derived, public Derived2
{
    int d3;
};

我想知道Derived3类的内存布局。我在网上查看了以下链接:

c++数据对齐/成员顺序&继承

C++ 继承内存模型

经过以上链接后,我觉得Derived3的内存布局可能是:

void* vtable_ptr1 //vtable pointer of Derived
int d //Derived
void* vtable_ptr2 //vtable pointer of Derived2
int d2 //Derived2
int b //Base? not sure where will this be.
int d3 //Derived3

在线编译器将Derived3的大小设置为 40 字节,所以我觉得(假设指针为 8 字节,int 为 4 字节)int b必须在vtable_ptr2 (8( vtable_ptr1 ) + 4( d ) + [4 padding] + 8之后( vtable_ptr2 ) + 4( d2 ) + 4( b ) + 4( d3 ) + [4 class padding]) 或之前vtable_ptr1 (4( b ) + [4 padding] + 8( vtable_ptr1 ) + 4( d ) + [ 4 填充] + 8( vtable_ptr2 ) + 4( d2 ) + 4( d3)) 以便填充出现并将类的大小增加到 40。

总而言之,我有以下问题:

顺序是否正确?如果不是,那么成员变量和 vtable 指针的正确顺序是什么?

4

1 回答 1

4

成员变量和 vtable 指针的正确顺序是什么?

没有“正确的顺序”。这在 C++ 标准中没有指定。每个编译器都可以以任何符合 C++ 标准的方式自由安排此类层次结构的内存布局。

在这种情况下,编译器可以根据一些固定的规则选择类的布局。或者,编译器可能会尝试在多种可能性中进行优化,并选择可以利用硬件相关因素的布局,例如对象的首选对齐方式,以尽量减少任何所需的填充。这完全取决于编译器。

此外:如果您查看 C++ 标准的文本,您将找不到任何关于“vtable”的内容。它不在那里。这只是虚拟类方法和虚拟继承最常见的实现机制。代替指针,它完全符合 C++ 标准,C++ 编译器使用两字节索引进入表,而不是整个指针——进入包含定义每个特定类的虚拟属性的记录的表。只要具有虚拟属性的所有类的数量不超过 65536,这将完全正常。

换句话说:无论如何,你不能保证这个类的布局是什么,在内存中,或者它的大小是什么。它没有在 C++ 标准中指定,完全由实现定义。

于 2022-01-07T12:07:10.303 回答