在開始處應該只有一個零(大小爲void *)(除非在沒有RTTI的情況下編譯)。它實際上不一定是,但它通常是,我會稍後解釋。
V表爲(至少GCC起源)的ABI看起來像:
class_offset
type_info
first_virtual_function
second_virtual_function
etc.
的TYPE_INFO可以是NULL
(0
)的情況下的代碼未經RTTI編譯。
上面的class_offset
解釋了爲什麼你在那裏看到零。這是擁有班級中的班級抵消。即具有:
class A { virtual meth() {} };
class B { virtual meth() {} };
class C: public A, public B { virtual meth() {} };
將導致進入主類C
,A
開始0
位置C
類和B
內開始在C
類內的位置4
(或8
)。
指針在那裏,所以你可以從任何類指針找到指向擁有對象的指針。因此,對於任何「主」類,它總是0
,但對於B
類虛擬表在C
有效的上下文中將是-4
或-8
。實際上,你需要檢查的虛函數表爲C(下半年),因爲編譯器通常不單獨產生的VTable:
_ZTV1C:
// VTable for C and A within C
.quad 0
.quad _ZTI1C
.quad _ZN1CD1Ev
.quad _ZN1CD0Ev
.quad _ZN1C4methEv
// VTable for B within C
.quad -8
.quad _ZTI1C
.quad _ZThn8_N1CD1Ev
.quad _ZThn8_N1CD0Ev
.quad _ZThn8_N1C4methEv
在早期編譯器被用來計算實際指向所屬的偏移類在調用方法之前。但是,因爲它直接在所屬的類調用方法時放緩的情況下,現代的編譯器而產生存根其中減去直接偏移並跳轉到主要實施方法(因爲你可以從方法名猜 - 注意8
):
_ZThn8_N1C4methEv:
subq $8, %rdi
jmp _ZN1C4methEv
檢查派生類的表。我敢打賭,前面沒有*零。 – wallyk
不,每一個我所見過的虛函數表,還有在前面的0。派生類或不,Vtable總是+ 8. –