#include <iostream>
class SuperBase
{
public:
    int Sb;
};
class Base1:virtual public SuperBase
{
public:
    int a;
};
class Base2:virtual public SuperBase
{
public:
    int b;
};
class Derived: public Base1,public Base2
{
public:
    int c;

};
int main()
{
    using namespace std;
    cout<<sizeof(Derived);
    return 0;
}



output is showing 24
but it should show 20 because
int sb 4 bytes
int a 4 bytes
int b 4 bytes
int c 4 bytes
vbptr 4 bytes
total 20 bytes

因为我们使用的是虚拟继承概念,所以int sb不应计算两次,不是吗?

最佳答案

24大概是:

Sb 的

  • 4
  • 4代表
  • 4代表b
  • 4对于c
  • 8用于虚拟继承的开销。

  • 在我的(32位)编译器上,sizeof(Derived)是24,而sizeof(Base1)是12,这表明开销并不总是8。

    我想这8个对象在Base1子对象的开始处包含一个vtable(或类似的)指针,而在Base2子对象中包含另一个vtable指针,当将该对象的指针转换为Base2*时将使用该指针。多重继承的问题在于,从对象开始到Base1的偏移量与从对象开始到Base2的偏移量不能相同。

    特别是,这意味着对于Base1和Base2中的一个,当其基类子对象Derived的偏移量与BaseN是最派生的类的偏移量不同。但是,当您强制转换为Base2 *时,结果值必须指向“看起来像” Base2的值。因此,在虚拟继承实际上导致共享基类的情况下,会产生一些额外的开销。

    另一种方法是将sizeof(SuperBase) 4,sizeof(Base1)sizoef(Base2)都设置为12(两个int和一个vtable指针),并且sizeof(Derived)等于28:Sb为4,a,b,c每个为4,ab和c分别为4三个vtable指针,分别位于Base1,Base2和Derived中。但是(我认为)您的编译器帮了您的忙,并且安排Derived的vtable指针与Base1的vtable指针放在同一位置,这与单继承是正常的。

    在所有情况下,当我说“vtable指针”时,它可能与虚拟函数所用的东西完全相同,也可能不同,但这是某种类元数据。也许它只是用于到达基类的指针或偏移量。

    我在这里画了一些小图,可能会有所帮助:

    Why can't you use offsetof on non-POD structures in C++?

    10-08 11:00