純粋仮想機能を配置する仮想テーブルはどれですか? 基本クラスまたは派生クラスで?
たとえば、仮想テーブルは各クラスでどのように見えるでしょうか?
class Base {
virtual void f() =0;
virtual void g();
}
class Derived: public Base{
virtual void f();
virtual void g();
}
g++ -fdump-class-hierarchy layout.cpp
ファイルを生成しますlayout.cpp.class
。の内容はlayout.cpp.class
次のとおりです。
Base の Vtable Base::_ZTV4Base: 4u エントリ 0 (整数 (*)(...))0 8 (整数 (*)(...))(& _ZTI4Base) 16 __cxa_pure_virtual 24 ベース::g クラスベース サイズ=8 整列=8 ベースサイズ=8 ベースアライン=8 ベース (0x7ff893479af0) 0 ほぼ空 vptr=((& Base::_ZTV4Base) + 16u) 派生用の Vtable 派生::_ZTV7派生: 4u エントリ 0 (整数 (*)(...))0 8 (int (*)(...))(& _ZTI7Derived) 16 派生::f 24 派生::g 派生クラス サイズ=8 整列=8 ベースサイズ=8 ベースアライン=8 派生 (0x7ff893479d90) 0 ほとんど空 vptr=((&派生::_ZTV7派生) + 16u) ベース (0x7ff893479e00) 0 ほとんど空 派生用のプライマリ (0x7ff893479d90)
の「純粋さ」を削除するとf
、5 行目が次のように変更されます。
16 ベース::f
各クラスには独自の vtable があります。f
inのエントリはにBase
なりNULL
、 in のエントリDerived
は実装されたメソッドのコードへのポインタになります。
vtable エントリは基本クラスになります。
なんで?派生型オブジェクトのアドレスを保持する基本ポインター型を持ち、基本型のポインター変数でメソッドを呼び出すことができるためです。
純粋仮想は、派生型が独自の実装を提供する必要があることをコンパイラに伝えるだけであり、基本クラスの実装に依存することはできません (基本クラスで指定されている場合でも)。
実際には両方で。pure_virtual_function_called()
基本クラスの vtable には、おそらくプログラムを中止するスタブのようなものを指す純粋仮想関数用のスロットがあり、派生クラスの vtable には実際の実装へのポインターがあります。