我正在努力更好地理解虚拟继承在实践中是如何工作的(也就是说,不是根据标准,而是在像g++
这样的实际实现中)。实际问题在底部,以粗体显示。
所以,我自己构建了一个继承图,其中包括这些简单的类型:
struct A {
unsigned a;
unsigned long long u;
A() : a(0xAAAAAAAA), u(0x1111111111111111ull) {}
virtual ~A() {}
};
struct B : virtual A {
unsigned b;
B() : b(0xBBBBBBBB) {
a = 0xABABABAB;
}
};
(在整个层次结构中,我还有C: virtual A
和BC: B,C
,因此虚拟继承是有意义的。)
我编写了几个函数来转储实例的布局,获取vtable指针并打印前6个8字节值(任意适合屏幕),然后转储对象的实际内存。这看起来像这样:
转储A
对象:
actual A object of size 24 at location 0x936010
vtable expected at 0x402310 {
401036, 401068, 434232, 0, 0, 0,
}
1023400000000000aaaaaaaa000000001111111111111111
[--vtable ptr--]
转储B
对象和A
对象所在的位置,通过在相应位置打印很多A
来表示。
actual B object of size 40 at location 0x936030
vtable expected at 0x4022b8 {
4012d2, 40133c, fffffff0, fffffff0, 4023c0, 4012c8,
}
b822400000000000bbbbbbbb00000000e022400000000000abababab000000001111111111111111
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA (offset: 16)
如您所见,A
的{{1}}部分位于B
字节到16
对象开头的偏移处(如果我已经实例化B
并将其dyn转换为BC
!)。
我原本期望B*
(或至少一个16
,由于对齐)显示在表格的某个地方,因为程序必须查找2
在运行时的实际位置(偏移量)。 那么,布局真的如何?
编辑:转储是通过致电A
和dump
:
dumpPositions