5 に答える
そんなメンバーいないから。virtual関数は、最初に宣言されたクラスからすべての派生クラスまで実行されます。泡立ちません。コンパイラが見ると、その型arr[ i ]->f2()の の定義を調べます。(静的) タイプを持っています。そのため、コンパイラはの定義を検索して の適切な定義を探しますが、何も見つかりません。したがって、診断。arrarrAAf2
virtual関数は安全にインライン化できます。実際、すべてのクラス内定義は、コンパイラによって暗黙的にインライン展開されます。したがって、あなたA::f1はすでにインライン化されています。
を呼び出そうとしていますが、f2()宣言していません。A*Af2()
virtualつまり、メソッドは、基本クラス(オブジェクト自体のクラスを含む)へのポインターを介して呼び出されると、呼び出し元のオブジェクトのvptrテーブルに基づいて、実行時に解決されます。基本クラスでメソッドを表示することはありません。
仮想関数のインライン化は非常に安全ですが、期待するパフォーマンスの向上が必ずしも得られるとは限りません。インライン化とは、関数コードが呼び出し時にコンパイラーによってコピーアンドペーストされることを意味します。インライン化とそれが空のパイである理由については、C++Super-FAQを参照してください。
インライン化はコンパイル時の概念です。基本クラスへのポインターで呼び出される仮想メソッド呼び出しは、実行時に解決されます。
つまり、仮想の関数への次の呼び出しをインライン化できます。
B myB("The B.");
b.f1(); // not virtual, might be inlined
最初は簡単:
また、仮想関数のインライン化は安全ですか?
はい、仮想関数はインライン化できますが、ポリモーフィズムは常に機能することが保証されています。
例えば:
B b;
b.f2();
コンパイラはオブジェクトのタイプが であることを認識しているため、仮想テーブルを使用せずにコンパイル時に解決できBます。
arr[1] が B にアップキャストされている場合でも、_vptr が基本クラスの VTABLE を指すのはなぜでしょうか。
そうではありません。これは class の仮想テーブルを指していますBが、コンパイラはそれを認識しません。仮想テーブルは実装の詳細です。で関数を呼び出しているA*ため、Bのメソッドは表示されません。この単純な例では簡単ですが、一般に、コンパイラはそれが事実arr[1]へのポインタであることをどのように判断できるのBでしょうか? それがポリモーフィズムの要点です。派生型を抽象化します。
あなたができることは次のとおりです。
dynamic_cast<B*>(arr[1]) ? (dynamic_cast<B*>(arr[1]))->f2() : (void)0;
このように考えてみてください。arr[i]コンパイル時に、コンパイルは、指しているオブジェクトの実際の型を完全に認識しません。その型は実行時にのみ認識されます。したがって、次のように書くと:
arr[i]->f2();
コンパイラは、その呼び出しを行うために生成するコードを知りません。f2とは?Bで宣言されているのはf2ですか?C という名前の A のサブクラスもあり、そのサブクラスにも f2 という名前の仮想関数があり、arr[i] が指すオブジェクトがたまたま C 型である場合はどうなるでしょうか。わかりません。
このような場合の唯一の正常な動作は、エラーを生成することであることがすぐにわかります。
arr[1]A*というメソッドを持たない型f2です。にキャストarr[1]するB*必要がありますが、それは良い考えではないと思います。代わりにデータ構造を変更してください。