2012-04-08 4 views
2

バーチャルテーブルでコンパイラが仮想ファンクションに出会うたびに、Vtableが作成され、そこに仮想ファンクションアドレスが配置されます。それは継承する他のクラスでも同様に起こります。各Vtableを指す各クラスに新しいポインタを作成しますか?派生クラスの新しいインスタンスが作成され、ベースPTRに割り当てられたときに、Virtual関数にアクセスする方法はありませんか?バーチャルファンクションのVtableの動作方法

+0

[仮想テーブルC++](http://stackoverflow.com/questions/2173493/virtual-table-c) –

答えて

1

仮想関数を持つ各クラスについて、vtableが作成されます。次に、実行可能なクラスのオブジェクトがコンストラクタを使用して作成されると、コンストラクタは適切なvtableをオブジェクトにコピーします。したがって、各オブジェクトにはvtableへのポインタがあります(または、複数の継承の場合は、必要に応じて、それぞれのvtableへのOrr)。コンパイラは、vtableがオブジェクトのどこにあるかを知っているので、仮想メソッドを呼び出す必要があるときはvtableを抑止するためにバイトコードを出力し、適切なメソッドを検索してそのアドレスにジャンプします。

単一継承の単純なケースでは、子クラスは親クラスのvtableのコピーで始まり、親クラスのメソッドをオーバーライドする子クラスの各仮想メソッドのオーバーライドされたエントリを取得します。 (と、それはまた親クラスのメソッドをオーバーライドししない子クラッド内のすべての仮想関数のための新しいエントリを取得します)

5

あなたは仮想関数を含むクラスを作成するか、またはあなた は、そのクラスから派生するたびに仮想関数が含まれている場合、コンパイラ は、そのクラスのための一意のVTABLEを作成します。

あなたは コンパイラは 派生クラスで基本クラスのバージョンのアドレスを使用して、基本クラスに仮想宣言された関数をオーバーライドしていない 場合。

次にVPTRをクラス に入れます。単純な 継承を使用する場合は、オブジェクトごとに1つのVPTRしかありません。 VPTRは、適切なVTABLEの開始アドレスの を指すように初期化されなければならない。 (これは コンストラクターで発生します) VPTRが適切なVTABLEに初期化されると、 のオブジェクトはそのタイプを「認識」します。しかし、この自己知識は、仮想関数が呼び出された時点で使用されない限り、 の価値はありません。 基本クラスのアドレス(初期バインディングを実行するために、コンパイラに の情報がすべて必要ない場合の の状況)を使用して仮想関数を呼び出すと、何か特別なことが起こります。 コンパイラ は、典型的な関数呼び出しを実行する代わりに、特定のアドレスへのアセンブリ言語CALLを実行する代わりに、コンパイラ が関数呼び出しを実行するために異なるコードを生成します。

+0

の可能な複製ですので、あなたのように言うことを意味します。 1つのVPTRのみがオブジェクトの作成中に特定のテーブルを指し、割り当て権の間は指しません。しかし、それは常にベースクラスに存在します。 – Naruto

+0

私が言ったように、コンパイラは、クラスとその派生クラスのためのユニークなVTABLEを作成します。 – IndieProgrammer

+0

VTABLEのVPTRはどうですか?派生クラスをインスタンス化してベースptrに割り当てると、どのように動作しますか? – Naruto

3

プログラムがクラスごとに仮想テーブルをコンパイルするたびに、vtableがクラスごとに作成されることが明らかになります。 実行時に、オブジェクトが作成されると、コンパイラはvptrをオブジェクトに割り当てます。vptrは、特定のクラスのオブジェクトの仮想テーブルを指します。 つまり、オブジェクト単位でvptrが作成されます。