了解虚拟派生类的大小 A的大小是4,因为它只有一个int B1的大小为16,因为(int+int+虚拟指针)与B2相同 但是,C的大小是如何为40??< /p>< p>免责声明:除了C++允许添加填充的事实之外,没有任何一个是由C++标准指定的,而且我还没有真正检查过任何汇编代码。

了解虚拟派生类的大小 A的大小是4,因为它只有一个int B1的大小为16,因为(int+int+虚拟指针)与B2相同 但是,C的大小是如何为40??< /p>< p>免责声明:除了C++允许添加填充的事实之外,没有任何一个是由C++标准指定的,而且我还没有真正检查过任何汇编代码。,c++,multiple-inheritance,virtual-inheritance,memory-layout,C++,Multiple Inheritance,Virtual Inheritance,Memory Layout,如果在x64体系结构上的GCC中编译,结构可能如下所示: 4 16 16 40 void C::foo() { B2::a = 1; B1::a = 2; std::cout << B2::a << " " << B1::a << " " << A::a; // Output: 2 2 2 } 通过检查每个结构()的对齐方式,我们可以看到A与4个字节对齐,在使用GCC编

如果在x64体系结构上的GCC中编译,结构可能如下所示:

4
16
16
40
void C::foo() {
    B2::a = 1;
    B1::a = 2;
    std::cout << B2::a << " " << B1::a << " " << A::a; // Output: 2 2 2
}
通过检查每个结构()的对齐方式,我们可以看到
A
与4个字节对齐,在使用GCC编译器时,所有剩余的结构都与8个字节对齐


我假设您的计算机采用x64体系结构。这意味着指针必须至少有8个字节长,并且由于vptr存在于
B1
B2
中,所以整个结构将对齐到8个字节。因此,编译器需要向这两个结构添加填充,以保持大小(B1)%alignof(B1)=0(或者简单地说是保持结构对齐)。

结果可能会因使用的编译器和系统体系结构而异。例如,
msvc 19.28 x64
给出了这个自解释的结果(使用选项
/d1reportAllClassLayout
获得它):

更新 应该注意的是,上面的类布局清楚地展示了虚拟继承的特性,其中只有基类实例(
a
)的一个副本被孙派生类(
C
)继承。如果
A::A
数据成员是公共的,我们可以在类
C
的成员函数中使用以下语句:

class C size(24):
    +---
 0  | +--- (base class B1)
 0  | | {vbptr}
 4  | | b1
    | +---
 8  | +--- (base class B2)
 8  | | {vbptr}
12  | | b2
    | +---
16  | c
    +---
    +--- (virtual base A)
20  | a
    +---
我们将有两个基类
A

class C size(20):
    +---
 0  | +--- (base class B1)
 0  | | +--- (base class A)
 0  | | | a
    | | +---
 4  | | b1
    | +---
 8  | +--- (base class B2)
 8  | | +--- (base class A)
 8  | | | a
    | | +---
12  | | b2
    | +---
16  | c
    +---
void C::foo(){
B2::a=1;
B1::a=2;

std::cout知道
C
的布局和填充方式并不十分重要,因为这是实现定义的,不同平台之间会有所不同。但有一个具体的细节

基类
A
,实际上是继承的,被提取到层次结构的顶部。因此,只要
B1
被“自己”使用,它就是
B1
的一部分。当它在
C
内部进一步继承时,
A
就不再是它的一部分

这意味着我们不能依赖于
sizeof(B1)
sizeof(B2)
,因为我们必须先从它们中减去
sizeof(A)
。但是从
B1
中删除4个字节并不会将其大小从16减少到12,因为由于vbptr,它必须对齐并填充到8个字节(假设64位)

所以我们最终得到了sizeof(B1减去A)
+
sizeof(B2减去A)
+
sizeof(A)
+
sizeof(C::C)
=16+16+4+4=40

如果我们把
A
放大,我们可以得到一些时髦的输出:

void C::foo() {
    B2::a = 1;
    B1::a = 2;
    std::cout << B2::a << " " << B1::a; // Output: 1 2. `A::a` ambiguity error
}
现在更清楚的是
sizeof(C)
sizeof(B1)
+
sizeof(B2)


要了解更多信息,您可以查看
C
的具体布局。

可以进行对齐和调整padding@drescherjm一切都是一个
int
。有什么可以对齐或填充?@Spencer可能这是x64架构,所以
vptr
是8字节。@Spencer vptr可能是8字节。40=16+16+
sizeof(int)
+填充到8的倍数,以满足指针的对齐要求。
void C::foo() {
    B2::a = 1;
    B1::a = 2;
    std::cout << B2::a << " " << B1::a << " " << A::a; // Output: 2 2 2
}
class C size(20):
    +---
 0  | +--- (base class B1)
 0  | | +--- (base class A)
 0  | | | a
    | | +---
 4  | | b1
    | +---
 8  | +--- (base class B2)
 8  | | +--- (base class A)
 8  | | | a
    | | +---
12  | | b2
    | +---
16  | c
    +---
void C::foo() {
    B2::a = 1;
    B1::a = 2;
    std::cout << B2::a << " " << B1::a; // Output: 1 2. `A::a` ambiguity error
}
#include <iostream>
using namespace std;
class A {
  int a1,a2,a3,a4,a5;
};
class B1 : virtual public A {
  int b1;
};
class B2 : virtual public A {
  int b2;
};
class C : public B1, public B2 {
  int c;
};

int main() {
  A obj1; B1 obj2; B2 obj3; C obj4;
  cout << "sizeof(A)  = " << sizeof(obj1) << endl;
  cout << "sizeof(B1) = " << sizeof(obj2) << endl;
  cout << "sizeof(B2) = " << sizeof(obj3) << endl;
  cout << "sizeof(C)  = " << sizeof(obj4) << endl;
  return 0;
}
sizeof(A)  = 20
sizeof(B1) = 32
sizeof(B2) = 32
sizeof(C)  = 56