#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不应该计算两次,不是吗?
发布于 2010-12-02 20:46:55
24可能是:
的开销
在我的(32位)编译器上,sizeof(Derived)是24,sizeof(Base1)是12,这表明开销并不总是8。
我猜8由一个vtable (或类似的)指针组成,位于Base1子对象的开头,另一个位于Base2子对象中,当指向该对象的指针转换为Base2*时,将使用该指针。多重继承的问题是,Base1距对象开头的偏移量不能与Base2距对象起点的偏移量相同。
特别是,这意味着对于Base1和Base2中的一个,当它是派生的基类子对象时,偏移量与BaseN是最派生的类时不同。但是当你强制转换为Base2*时,结果值必须指向“看起来”像Base2的值。因此,在虚拟继承实际上导致共享基类的情况下,会有一些额外的开销。
另一种方法是使sizeof(SuperBase) 4、sizeof(Base1)和sizoef(Base2)都为12 (两个it和一个vtable指针),并且sizeof(Derived)等于28: 4对于Sb,4分别对于a、b、c和4对于三个vtable指针,在Base1、Base2和派生中各一个。但是你的编译器(我认为)帮了你一个忙,并且安排了派生的vtable指针与Base1的vtable指针在同一位置,这对于单继承来说是很正常的。
在所有情况下,当我说"vtable指针“时,它可能是也可能不是用于虚函数的完全相同的东西,但它是某种类元数据。也许它只是一个指针或偏移量,用于到达基类。
我在这里画了一些可能会有帮助的小图表:
发布于 2010-12-02 20:53:47
通常,通过虚拟继承从其他类继承的类需要额外的指针或偏移量,以指示它们继承的每个虚拟基址所在的位置。根据它们所属的完整对象的类型,不能假设虚拟基地处于相同的相对位置。
指针实际上不需要指向基类本身,编译器可能会插入类型信息结构的id,该结构可以用来计算出对象的完整布局,但通常需要一些东西,以便当代码通过指针或引用使用像Base1这样的类时,它将始终工作,而不管特定Base属于哪个完整对象。
这意味着Derived中的Base1和Base2的大小可能类似于sizeof(int) + sizeof(void*),在典型的32位编译器上,除了SuperBase的大小和Derived的成员的总大小之外,还有8个字节。
发布于 2010-12-02 20:56:27
记住要查看所有的大小-这样可以更容易地看到可能发生的情况。
在本例中,在我测试的编译器上,拥有一个虚拟基类会给Base1和Base2各增加4字节的开销。
SuperBase 4
Base1 12
Base2 12
Derived 24https://stackoverflow.com/questions/4335071
复制相似问题