2011-08-26 11 views
9

私は新しいので、私の上で簡単に行く:) 私の講師がしばらく前に言ったから、仮想テーブルの順序が重要です。 しかし私はその理由を理解していない!!次のコードを考える仮想テーブルの順序は重要ですか?

class A 
{ 
public: 
    A() {cout <<"1" << endl;}; 
    A (const A& s) {cout << "2" << endl;} 
    ~A() {cout << "3" << endl;} 
    void f1() {cout << "4" << endl; f2();} 
    virtual void f2() = 0; 
    virtual void f3() {cout << "5" << endl;} 

}; 


class B : public A 
{ 
public: 
    B() {cout << "6" << endl;} 
    B(const B& b) : A(b) {cout << "7" << endl;} 
    ~B() {cout << "8" << endl;} 

    virtual void f1() {cout<<"9"<<endl;} 
    void f2() {cout<<"lO"<<endl; f4();} 
    virtual void f2(int i) {cout << "11" << endl;} 
    virtual void f4() {cout << "12" << endl; f3();} 

}; 

を彼は順序があることを言った:

A's vtable : 
A::f2() 
A::f3() 

B's vtable : 
B::f2() 
A::f3() 
B::f1() 
B::f2(int) 
B::f4() 

しかし、それは重要である理由を私は理解していませんか?彼はそれが正確な順序ではない である場合、vtableは役に立たないと言った、あなたはなぜ説明できますか?

答えて

8

vtableの順序は、正常に動作するためには重要ですが、コンパイラに対してのみ重要です(つまり、世話をするため気にする必要はありません)。

コンパイラが関数をオフセットで参照するため(つまり、オフセットによって致命的なランダム関数が生成されるため)、コンパイラがそれ自体のために順序を狂わせた場合、関数が破損します。しかし、平均的なプログラマは、 vtableの順序を心配する必要はありません。

1

vtableは「ルックアップ」テーブルです。基本的には、クラスの仮想関数へのポインタのマップです。順序が間違っていると、ポインタは間違った関数を指します。たとえば、B:f1()を呼び出す場合は、引数を取らず、代わりにB::f2()と呼びます(int)。

16

C++標準ではvtableという概念はありません。ほとんどの実装(すべてではないにせよ)が仮想ディスパッチのためにそれを使用しているということだけです。しかし、厳密な規則は完全に実装定義されています。

言われました...関数の順序は重要ですが、プログラマーにとってではなく、コンパイラーにとっては重要です。あなたのコード内にあなたの関数を配置することができます。ただし、コンパイラは通常、各関数ポインタをvtableの特定の場所に配置します。vtableは、その関数専用です。したがって、f()を呼び出す必要があるときは、f()関数のインデックスを知っていて、そのポインタをvtableから受け取ります。

この質問は同様にあなたを助けるかもしれない:Virtual dispatch implementation details

+0

ありがとうございます!皆さんに! –

+1

@Ron_s質問に答えた場合は、この回答の左上にあるチェックマークをクリックしてください。 –

2

のvtableのすべてのクライアントは、彼らがコールする権利の方法を見つけることができるように、正しい順序を知る必要があります。しかし、すべての当事者が注文に同意する限り、その注文が何であるかは関係ありません。

5

クラスが外部ABI(たとえば、COM/XPCOM)のインターフェイスを宣言するときだけ重要です。

ほとんどの場合、重要ではなく、気にする必要はありません。

+1

+1外部abiは非常に良い点です –

+2

+1 vtableのレイアウトがWindowsプラットフォーム上で標準である唯一の理由はCOMのためです。コンパイラベンダーとして、COMをサポートしたい場合は、Microsoftの実装に従わなければなりません。ただし、仮想継承や非インターフェイスの多重継承など、COMで使用されていないより高度な機能は実装に依存します。 –

0

私は彼が何を意味するのかわからないんだけど、私はそれがどのように動作するかを説明してみましょう:すべての

まず、C++は名前と署名によってメソッドを定義します。したがって、C++がクラスの仮想テーブルを開始すると、すべての基本クラスの仮想関数が、同じ名前とシグネチャを持つ派生した仮想関数に置き換えられます。

クラスが別のクラスを派生させるとき、それは実際にそのクラス上に構築されます。だから、基本クラスは、メモリブロックの一部として存在している(複雑、ここで読む - Virtual inheritance

仮想テーブルがちょうど実行時に種類に応じて右機能への「ポインタ」を開催。

関連する問題