#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 的
在我的(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++?