c++中虚拟继承的对象布局
object layout of virtual inheritance in c++
- c++中虚拟继承的对象布局
- 如何解释下面的结果
环境与2008年相比
#include <iostream>
using namespace std;
class A {
public:
virtual ~A();
virtual void foo();
};
class B : public virtual A {
public:
virtual ~B();
virtual void foo();
};
class C : public virtual A {
public:
virtual ~C();
virtual void foo();
virtual void foobar();
};
class D : public B, public C {
public:
virtual ~D();
virtual void foo();
virtual void foobar();
};
int main()
{
cout<<"size of A "<<sizeof(A)<<endl;
cout<<"size of B "<<sizeof(B)<<endl;
cout<<"size of D "<<sizeof(D)<<endl;
cout<<"size of C "<<sizeof(C)<<endl;
}
结果是:
size of A 4
size of B 12
size of D 20
size of C 16
正如您在这个SO问题中看到的,在关于对象内存布局的标准中只定义了很少的内容。大部分布局是由实现定义的。当您提到MSVC实现时,出于好奇,让我们来看看这些(不可移植的)实现细节。
简单继承:
我建议您从没有虚拟功能的简单非虚拟继承开始:
class X { }; // size of X 1
class Y : public X { }; // size of Y 1
所有对象都必须具有非null大小(这仍然是标准大小)。这就是为什么我们看到1,尽管X是完全空的。注意,Y的大小与X相同,因为Y中没有添加任何内容(因此Y已经是非空大小)。
简单继承,具有虚拟函数:
当您开始使用虚拟函数时,MSVC会在对象的开头添加一个指向vtable的指针。这个SO问题展示了在简单继承的情况下vtable的原理。
class XF // size of XF 4
{ public: virtual void foo(){} };
class YF : public XF // size of YF 4
{ public: virtual void bar(){} };
class YX : public X // size of YX 4
{ public: virtual void bar(){} };
您可以在这里看到vtable指针的大小是4。你可以立即推断出我是在32位模式下编译的,因为在x64模式下你会有8。
顺便说一句,为了多态性的目的,单个继承类的vtable被合并(在派生对象的开头只有一个vtable指针)。更多关于vtables的信息,请参阅这篇非常有趣的DDJ文章中的signle an multiple heritage。
没有虚拟继承的多重继承:
多重继承组合了所有继承的类,因此它的大小至少与继承类的大小相加一样大。
但由于对齐要求,它可能会更大,在虚拟函数的情况下,还有一个额外的vtable指针(合并不再像单一继承那样可能)。DDJ的文章也对此进行了解释。
虚拟继承:
让我们看看虚拟继承(与虚拟函数无关)的效果:
class ZX : public virtual X { }; // size of ZX 4
class ZF : public virtual XF { }; // size of ZF 8
class ZZF: public virtual ZF { }; // size of ZZF 12
所以我们看到,无论何时进行虚拟继承,都会添加一个指针。这样做的目的是什么?
在没有虚拟固有性的情况下,从派生对象到其基础的上转换是直接的。
但对于虚拟继承,这种升级是一场噩梦,因为几个类共享同一个基类。因此,基类可能不再与派生类相邻。这就是虚拟继承需要指向虚拟基表的指针的原因对于每个虚拟继承。
- 什么时候调用组成单元对象的析构函数
- 对RValue对象调用的LValue ref限定成员函数
- CMake-按正确顺序将项目与C运行时对象文件链接
- 空基优化子对象的地址
- 如何在qt中将对象添加到现有布局中?--已解决
- C++对象布局是否必须静态定义?
- 在C++标准中记录对象的内存布局的哪个位置?
- 在标准布局对象中进行指针运算(例如,使用偏移量)时,我们是否需要使用 std::launder?
- 何时可以与相应的完整对象类型具有不同的布局
- 非结构对象布局
- C++对象内存布局
- 对象/结构等的C++内存布局是什么?
- 对象的布局
- c++中虚拟继承的对象布局
- 公共和私有对对象的内存布局是否有任何影响
- 对象的二维几何布局
- 包含容器的对象的C++布局
- 关于对象内存布局的假设
- C++11 标准是否保证initializer_list对象的内存布局与交叉编译器兼容?
- 编译器构造 - C++中多个继承对象的内存布局