2012-06-25 1 views
11

インターフェイス(多相クラスは純粋仮想関数のみ)はvtableを持っていますか? インタフェースは多相関数を実装しておらず、直接構築できないため、リンカがvtableを配置する必要はありません。そうですか?私は特にMSVCコンパイラを心配しています。インターフェイスvtable

+0

MSVCの 'declspec(novtable)'機能は、インターフェイス、特にCOMのものにvtableを省略することができます。これは、継承(単一の継承を強制しますが、最終オブジェクトには他のものよりも多くの多型性を提供する単一の表しか持たないようにします)に関して、興味深く重要な意味を持ちます。 – ssube

答えて

6

はい、彼らが行います。それにはいくつかの理由があります。

最初の正当な理由は、純粋な仮想メソッドでも実装があることです。暗黙的または明示的です。純粋な仮想関数を呼び出すトリックを引き出すことは比較的簡単です。したがって、基本的にあなたの定義を提供し、呼び出すことができ、何が起こるか見ることができます。そのため、最初に仮想テーブルが存在するはずです。

仮想テーブルをすべてのメソッドが純粋仮想であり、他のデータメンバーがない場合でも、仮想テーブルを基本クラスに置く別の理由があります。多型を使用すると、基本クラスへのポインタがプログラムの全周を渡されます。仮想メソッドを呼び出すために、コンパイラ/ランタイムは、基本ポインタからの仮想テーブルの相対的なオフセットを把握する必要があります。 C++に多重継承がない場合は、抽象基本クラス(たとえば)からオフセットをゼロにすることができます。この場合、vtableを持たない可能性があります(ただし、理由#1のために必要です)。しかし、複数の継承があるので、基本クラスの数(および型)に応じて2つまたは3つのvtableが存在する可能性があるため、トリックala「vtableは0のオフセットにあります」が機能しません。

他にも理由はありますが、それ以外の理由もあります。

希望します。

+0

良い議論!それを考えなかった。 –

+2

あなたが参照するトリックは、純粋な仮想関数を(_odr_ルールの下で)定義する必要がないか、そうでなければそのようなトリックを認識していないために定義されていない動作を引き起こすものではありませんか? –

+3

あなたの最初の理由で私は確信していません。私は純粋仮想関数を呼び出す唯一の方法は、(a)vtableを使用しない非仮想的に呼び出すか、(b)部分的にコンストラクタ/デストラクタから呼び出すことによって未定義の動作を呼び出すことですそれをすべて呼び出す必要はありません。それとも私がしない別のトリックを知っていますか? –

5

純粋にC++の観点からは、学問的な質問です。移植可能な方法がない場合、仮想関数をvtableで実装する必要はありません。

特にMSVCコンパイラについて心配しているのであれば、インターフェイスを__declspec(novtable)で飾りたいかもしれません。

(一般的に、一般的な実装では、抽象クラスは、例えば、仮想テーブルを必要とするかもしれない:

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; 
} 

+0

仮想テーブルを使用しない方法や、少なくとも「sizeof(void *)」を「開始点」として使用するクラスに追加する必要がある方法を、どのように実装できるか見てみたいのですが... –

+1

@VladLazarenko: vptr/vtableベースのソリューションが最適であることはほぼ普遍的に受け入れられているが、何らかの形式の動的型情報にアドレスのマップを格納するなどの非実用的な実装は少なくとも理論的に可能である。 –

+0

あなたはポイントを持っています。私が意味することは、あなたがそれをどのように呼んでも、アクセスするための少なくともいくつかの出発点が必要であることです。vtableへのポインタ、アドレス付きハッシュへのポインタ、ポインタ。 –

1

vtableは必須ではありませんが、めったに最適化されません。 MSVCは__declspec(novtable)という拡張子を提供しており、vtableを削除できることをコンパイラに明示しています。それがない場合、コンパイラはvtableが使用されていないことを自分自身でチェックする必要があります。これは例外的に難しいことではありませんが、まだまだ些細なものではありません。また、通常のコードでは実際の速度の利点を提供しないので、私が知っているコンパイラではチェックは実装されていません。

関連する問題