RTTIなしでコンパイルした場合を除き、冒頭にゼロ(size void *)の値が1つだけ存在する必要があります。実際にはそうである必要はありませんが、一般的には後で説明します。
仮想テーブルは、のために(少なくともGCCが発信)のABIは、次のようになりますTYPE_INFOコードがRTTIなしでコンパイルした場合にNULL
(0
)とすることができる
class_offset
type_info
first_virtual_function
second_virtual_function
etc.
。
上記のclass_offset
は、そこにゼロが表示される理由を説明しています。これは、所有するクラス内のクラスオフセットです。私。有する:
class A { virtual meth() {} };
class B { virtual meth() {} };
class C: public A, public B { virtual meth() {} };
クラスC
内に位置4
(又は8
)から始まるクラスC
とB
内に位置0
始まるメインクラスC
、A
に生じるであろう。
ポインタがあるので、クラスポインタから所有オブジェクトへのポインタを見つけることができます。したがって、「メイン」クラスの場合は常に0
になりますが、コンテキストで有効なB
クラス仮想テーブルの場合は-4
または-8
になります。あなたは、実際には通常、別々のvtableを生成しないコンパイラとしてCのための仮想テーブル(後半)をチェックする必要があります。以前のコンパイラで
_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
いいえ、私が見たすべてのvtableのために、正面に0があります。派生クラスかどうか、vtableは常に+ 8です。 –