我試圖更好地理解虛擬繼承在實際中如何工作(即,不是按照標準,而是在像g++
這樣的實際實現中)。真正的問題在底部,用粗體表達。虛擬繼承表如何在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
S表示。
actual B object of size 40 at location 0x936030
vtable expected at 0x4022b8 {
4012d2, 40133c, fffffff0, fffffff0, 4023c0, 4012c8,
}
b822400000000000bbbbbbbb00000000e022400000000000abababab000000001111111111111111
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA (offset: 16)
正如你所看到的,B
的A
部位於一個的16
字節偏移到B
對象(可以是不同的起點,如果我實例化BC
它DYN-澆鑄爲B*
!)。
我本來期望的16
(或至少是2
,由於對齊),以某處顯示在表,因爲該方案具有在運行時查找的A
實際位置(偏移)。 那麼,佈局怎麼樣?
編輯:轉儲是通過調用dump
和dumpPositions
完成:
using std::cout;
using std::endl;
template <typename FROM, typename TO, typename STR> void dumpPositions(FROM const* x, STR name) {
uintptr_t const offset {reinterpret_cast<uintptr_t>(dynamic_cast<TO const*>(x)) - reinterpret_cast<uintptr_t>(x)};
for (unsigned i = 0; i < sizeof(FROM); i++) {
if (offset <= i && i < offset+sizeof(TO))
cout << name << name;
else
cout << " ";
}
cout << " (offset: " << offset << ")";
cout << endl;
}
template <typename T> void hexDump(T const* x, size_t const length, bool const comma = false) {
for (unsigned i = 0; i < length; i++) {
T const& value {static_cast<T const&>(x[i])};
cout.width(sizeof(T)*2);
if (sizeof(T) > 1)
cout.fill(' ');
else
cout.fill('0');
cout << std::hex << std::right << (unsigned)value << std::dec;
if (comma)
cout << ",";
}
cout << endl;
}
template <typename FROM, typename STR> void dump(FROM const* x, STR name) {
cout << name << " object of size " << sizeof(FROM) << " at location " << x << endl;
uintptr_t const* const* const vtable {reinterpret_cast<uintptr_t const* const*>(x)};
cout << "vtable expected at " << reinterpret_cast<void const*>(*vtable) << " {" << endl;
hexDump(*vtable,6,true);
cout << "}" << endl;
hexDump(reinterpret_cast<unsigned char const*>(x),sizeof(FROM));
}
這將是很好/有助於看到'轉儲'的代碼。 – gbulmer 2012-03-30 17:40:58
@gbulmer:你走了。雖然我不認爲它有多大的幫助。 – bitmask 2012-03-30 17:45:05