0

ではdynamic binding、ポインタが指しているオブジェクトのタイプに基づいて、関数呼び出しが関数実装にバインドされます。

次のコードがあるとします。

base *bptr = new derived;
bptr->func();

関数funcを基底クラスで virtual と宣言します。次に、動的バインディングにより、仮想関数の派生クラスのバージョンがfunc実行時に呼び出されます。

上記の考え方は理解できました。

しかし、上記の概念を研究した後に研究した次の概念に混乱しました。

上記のコード スニペットでは、派生クラス オブジェクトへのポインターが基本クラス オブジェクトへのポインターに暗黙的に変換されます。次にbptr、実際には派生クラス オブジェクトの基本クラス サブオブジェクトを指し、派生クラス オブジェクトを指しません。

基本クラスのポインターbptrは基本クラスのサブオブジェクトを指しているため、実行時に基本クラスのバージョンの仮想関数funcを呼び出すべきではありませんか?

4

3 に答える 3

3

動的バインディングが実際に意味するものを見逃しているようです。これは、ポインターが (静的に) ベース サブオブジェクトを参照している場合でも、呼び出しが完全なオブジェクトの (動的) 型にディスパッチされることを正確に意味します。

一般的な実装は、仮想関数テーブルによるものです。ベース サブオブジェクトは、それが属する実際の完全な型の仮想関数テーブルへのポインターを隠しメンバーとして格納します。仮想関数 (動的ディスパッチが無効になっていないもの) へのすべての呼び出しは、最終的なオーバーライドが呼び出されることを保証する追加レベルの間接化を通じてルーティングされます。

そのテーブルと隠しポインターの管理方法の詳細については、コンパイラーは仮想関数を使用して型ごとにテーブルを作成し、さまざまなコンストラクターにコードを挿入して、それに応じてポインターを更新します。そのため、基本サブオブジェクトを構築している間、ポインターは基本 vtable を参照しますが、派生コンストラクターに入る前に、挿入されたコードは派生 vtable を参照するように (基本で) ポインターを更新します。

于 2012-01-27T12:56:22.470 に答える
1

それに惑わされないでください。「派生クラス オブジェクトへのポインターは、基本クラス オブジェクトへのポインターに暗黙的に変換されます」 - このステートメントの重要性は、 に存在しないderived何らかのメソッドがあると仮定することです。ここで試してみると、実際に のオブジェクトを参照している場合でも、エラーが発生します。derivedOnly()basebptr->derivedOnly();derived

だから、bptr確かにへのポインタbaseです。

于 2012-01-27T12:57:00.667 に答える
0

この例では:

base *bptr = new derived;
bptr->func();

このbaseクラスは、派生オブジェクトインスタンスを指しているため、呼び出すことができるメソッドを知るためのインターフェイスとして何らかの形で使用されます。vtable(http://en.wikipedia.org/wiki/Virtual_method_table)は、derivedクラスのメソッドが呼び出されるようにします。

于 2012-01-27T12:53:48.270 に答える