下面我们来看虚继承。首先看看这C020类,它从C010虚继承:
struct C010 { C010() : c_(0x01) {} void foo() { c_ = 0x02; } char c_; }; struct C020 : public virtual C010 { C020() : c_(0x02) {} char c_; }; |
PRINT_SIZE_DETAIL(C020) |
The size of C020 is 6 The detail of C020 is c0 c2 45 00 02 01 |
C020 c020; c020.C010::c_ = 0x04; |
0042387E mov eax,dword ptr [ebp+FFFFF82Ch] 00423884 mov ecx,dword ptr [eax+4] 00423887 mov byte ptr [ebp+ecx+FFFFF82Ch],4 |
前面说过对象的起始是一个指针,第1行指令取到这个指针的值,第2行把这个指针指向的地址后移4字节后的值(做为一个4字节的值)取出来。执行完这句我们看看ecx寄存器,可知取出来的值为5.最后一行是真正的赋值指令,它通过在对象的起始处(即[ebp+FFFFF32Ch])加上ecx中的值做偏移值(即5)来得到赋值的目的地址。接合前面的对象布局输出,我们可以发现从对象起始地址开始加5字节的偏移值,刚好得到父类的成员变量的地址。这样我们可以大致分析出直接虚继承的子类的对象布局。