インターフェイス(純粋仮想関数のみを持つポリモーフィッククラス)にはvtableがありますか?インターフェイスはそれ自体でポリモーフィック関数を実装せず、直接構築できないため、リンカがvtableを配置する必要はありません。そうですか?私は特にMSVCコンパイラについて心配しています。
3 に答える
はい、彼らはやる。そして、それにはいくつかの正当な理由があります。
最初の正当な理由は、純粋仮想メソッドでさえ実装されていることです。暗黙的または明示的。純粋仮想関数を呼び出すトリックを実行するのは比較的簡単なので、基本的に、自分の1つに定義を提供し、それを呼び出して、何が起こるかを確認できます。そのため、そもそも仮想テーブルが必要です。
すべてのメソッドが純粋な仮想であり、他のデータメンバーがない場合でも、仮想テーブルを基本クラスに入れるもう1つの理由があります。ポリモーフィズムが使用される場合、基本クラスへのポインターがプログラム全体に渡されます。仮想メソッドを呼び出すために、コンパイラ/ランタイムは、ベースポインタからの仮想テーブルの相対オフセットを把握する必要があります。C ++に多重継承がない場合、(たとえば)抽象基本クラスからのオフセットがゼロであると想定できます。その場合、そこにvtableがない可能性があります(ただし、理由#1のために必要です)。ただし、多重継承が関係しているため、基本クラスの数(およびタイプ)によっては2つまたは3つのvtableが存在する可能性があるため、「vtableは0オフセットにあります」というトリックは機能しません。
私が考えていない他の理由もあるかもしれません。
それが役に立てば幸い。
純粋にC++の観点からは、これは学術的な問題です。仮想関数は、移植可能な方法がない場合は、vtablesを使用して実装する必要はありません。
MSVCコンパイラについて特に懸念がある場合は、インターフェイスをで装飾することをお勧めします__declspec(novtable)
。
(一般に、一般的な実装では、抽象クラスにvtableが必要になる場合があります。例:
struct Base {
Base();
virtual void f() {}
virtual void g() = 0;
};
void h(Base& b) {
b.f(); // Call f on a Base that is not (yet) a Derived
// vtable for Base required
}
Base::Base() {
h(*this);
}
struct Derived : Base {
void g() {}
};
int main() {
Derived d;
}
)。
vtableは必要ありませんが、最適化されることはめったにありません。MSVCは__declspec(novtable)
拡張機能を提供します。これは、vtableを削除できることをコンパイラーに明示的に通知します。それがない場合、コンパイラはvtableが使用されていないことを自分自身でチェックする必要があります。これは例外的に難しいことではありませんが、それでも些細なことではありません。また、通常のコードでは実際の速度の利点が得られないため、私が知っているコンパイラではチェックが実装されていません。