考虑以下代码:
class A {
public:
virtual ~A();
virtual void foo();
};
class B : public A {
public:
virtual ~B();
virtual void foo();
};
B类对象在内存中的布局如下:
当我们谈论多重继承时,尤其是当我们谈论菱形继承,或者当我们谈论诸如以下的虚拟类时,很难在内存中布置某个类的对象:
class E : public C, public virtual D, public virtual B {
public :
E() {
cout << "E::E()" << endl;
}
E(int x) : D(x) {
cout << "E::E(int)" << endl;
}
};
我正在寻找一些伪算法,该伪算法说明如何显示此布局。有没有我可以遵循并手动构建这些布局(没有虚拟表)的算法?
编辑:我得到以下示例:
解决方案部分的内存布局为:
我只是不明白为什么这样显示。因此,我认为可以遵循某种算法来构建它。
答案 0 :(得分:2)
该布局取决于编译器定位的ABI。您应该研究ABI的文档,以了解如何在内存中布置类。
例如,GCC使用Itanium ABI。
答案 1 :(得分:0)
我将假设您得到的图认为C ++是具有附加功能的C,并从该角度对实现定义的行为进行了假设。
它正在从左到右读取 base-specifier-list ,首先是深度,并假设虚拟继承是单个指针。每个带标签的框对应于类的非静态数据成员子对象(没有子类)。未标记的框是指向虚拟基础的指针。
我们从E
开始。它具有一个非虚拟C
基,一个虚拟B
基和一个虚拟D
基。
C
有一个虚拟的B
子对象,它成为一个指针。
虚拟B
已具有一个指针,该指针将指向与C
的基址相同的位置。
虚拟D
需要一个指针。
这结束了E
的非虚拟基础,但是仍然有尚未存储的虚拟基础。
我们制作一个B
,它具有一个非虚拟的A
,并将偏移量记录在E
中。
我们制作一个D
,它具有一个非虚拟的B
,它具有一个非虚拟的A
,并将偏移量记录在E
答案 2 :(得分:0)
除标准布局类型外,它是实现定义的,也许也未指定:
对于多种继承模式,您可以使用static_cast来了解布局的方式-即使在那时也没有gaurentee:这看起来像这样:
void* offsetToB = static_cast<B*>(static_cast<A*>(nullptr));
免责声明:这是不安全的。