2011-07-07 9 views
8

私がCPPを知っているので、各クラスには独自のvtableがあります。仮想テーブル/ディスパッチテーブル

しかしthis Wikipediaのリンクは言及:

をオブジェクトのディスパッチテーブル は、オブジェクトの 動的にバインドメソッドのアドレスが含まれています。メソッド の呼び出しは、オブジェクトの ディスパッチテーブルから メソッドのアドレスをフェッチすることによって実行されます。ディスパッチテーブルは、同じクラスの に属するすべてのオブジェクトに対して同じ であり、通常はそれらの間で共有される です。

誰かが光を放つことができますか?

ありがとうございます!

+0

注 - C++のすべてのクラスにvtableがあるわけではありません。仮想関数を持つものだけが持っています。仮想関数がない場合、すべてのメソッドを(コンパイル時に)静的にバインドすることができ、実行時にディスパッチ・メカニズムは不要です。 – eran

答えて

3

はい、仮想メソッドは、コンパイラとランタイムによって別々に扱われます。

Java: Javaのすべてのメソッドは、デフォルトでは仮想です。つまり、そのメソッドがfinalまたはstaticとして宣言されている場合を除き、継承で使用すると、すべてのメソッドをオーバーライドできます。 VM Specificationから

Java仮想マシンがない 任務のオブジェクトの任意の特定の内部構造 ありません。ブックマーク はあり状態:メソッドを含む テーブルに1:Java仮想マシン の日の 実装のいくつかでは、クラス インスタンスへの参照が は、一対のポインタそのものであることをハンドルへのポインタであります オブジェクトのタイプを表すクラス オブジェクトへのポインタと、オブジェクト オブジェクトのヒープから割り振られたメモリ に、もう1つは、 オブジェクトのタイプを表すクラス オブジェクトへのポインタです。


C++:クラスのメンバ関数を仮想として宣言されるたびに

、コンパイラはそのクラスの仮想 として宣言されているすべての関数ポインタを含むメモリ内の 仮想テーブルを作成し、 。これは実行時の多型性を可能にする(すなわち実行時に所望の 機能を見つける)。仮想関数テーブルには、vtableオブジェクトの にも追加ポインタがあります。この追加ポインターとvtableはオブジェクトのサイズを増加させるので、クラス設計者は仮想関数の宣言について賢明である必要があります。

ベースのオブジェクトポインタのメソッドを呼び出したときの一連のイベントは次のとおりです。

  • はvtableのポインタ(vtableのの初めに、このvtableのポインタポイント)を取得します。
  • オフセットを使用してvtableの関数ポインタを取得します。

vtableポインタを使用して関数を間接的に呼び出します。

0

この引用符は、各オブジェクトに同じクラスのすべてのインスタンスで同じであるため、クラス間で共有できるディスパッチテーブルがあることを指摘しています。 I.各クラスには独自のvtableがあります。

+0

thnx ..あなたは他の方法で丸めていることを意味しています..各クラスはそのインスタンスによって共有されるディスパッチテーブルを持っています[オブジェクト] – codeObserver

1

仮想関数を持つすべてのクラス(Javaでは、すべてのクラスのみ)は、独自のvtableを持っています。各オブジェクトはクラスvtableへの参照を隠しています。したがって、同じクラスのオブジェクトには同じ参照があります。 、それは静的発することができるコンパイラはオブジェクトの特定の型を推論することができれば、

obj.vtable[idx_method](obj, args); 

たまに何かに翻訳され

obj.method(args); 

はあなたが作るときに仮想メソッドコンパイラの呼び出しは、通常のルックアップを行い仮想の代わりに呼び出します。だから、コード

MyObject obj(ctor_args); 
.... 
obj.method(args); 

は通常、仮想呼び出しよりも高速に実行されます

MyObject_method(obj, args); 

に変換することができます。

9

これは一例で理解することは時々簡単です:だから

class PureVirtual { 
    public: 
     virtual void methodA() = 0; 
     virtual void methodB() = 0; 
}; 

class Base : public PureVirtual { 
    public: 
     virtual void methodA(); 
     void methodC(); 
    private: 
     int x; 
}; 

class Derived : public Base { 
    public: 
     virtual void methodB(); 
    private: 
     int y; 
}; 

、それはのように見えるかもしれない派生型のオブジェクト与えられた:見て何か「派生」タイプのためのVtableで

      ------------ 
Known offset for vtable | 0xblah | -------> [Vtable for type "Derived"] 
         ------------ 
Known offset for x  | 3  | 
         ------------ 
Known offset for y  | 2  | 
         ------------ 

like:

"methodC"は仮想ではないため、vtableにはありませんまったく。また、クラスDerivedのすべてのインスタンスは、同じ型の共有vtableオブジェクトへのvtableポインタを持つことにも注意してください。

C++とJavaの実装はわずかに異なりますが、アイデアは互換性がありません。主な違いは、概念的な観点からは、Javaメソッドは「final」と宣言されていない限り「仮想」であるということです。 C++では、関数vtableに明示的にキーワード "virtual"を指定する必要があります。 vtableにないものは、オブジェクトの実行時の型ではなくコンパイル時の型を使用して送出されます。