クラスは仮想メソッドを宣言する場合があると、コンパイラはvptrを使用する必要はありませんか?
-
22-09-2019 - |
質問
私は思っていました
たとえば、考えてみます。
#include <iostream>
struct FooBase
{
virtual void bar()=0;
};
struct FooDerived : public FooBase
{
virtual void bar() { std::cout << "FooDerived::bar()\n"; }
};
int main()
{
FooBase* pFoo = new FooDerived();
pFoo->bar();
return 0;
}
それは右、pFooためvptrを使用する必要はありませんので、は、この例では、コンパイラは確かに、コンパイル時にpFooのタイプがどうなるか知っていますか? コンパイラはvptrの使用を避けることができ、より興味深い例がありますか?
解決
ビルのhref <上= "https://stackoverflow.com/questions/2336107/are-there-cases-where-a-class-declares-virtual-methods-and-the-compiler-does-need/ 2336154#2336154" >アンドリュー・スタインの答えに、私はあなたにも、いわゆる時に知りたいと思うので、 『仮想関数の実行時のオーバーヘッドが』避けることができます。 (オーバーヘッドがあるが、それは心配についての小さなの、そしてまれ価値はあります。)
これは、vtableのポインタののスペースを避けるために、本当に難しいですが、ポインタ自体はあなたの例を含めて、無視することができます。 のpFoo の初期化は、そのスコープ内にあるため、コンパイラはそのpFoo->bar
がのFooDerived ::バーをを意味する必要があります知っている、とのvtableをチェックする必要はありません。単純なものから複雑なものまで、複数のvtableのルックアップを避けるために、いくつかのキャッシュ技術もあります。
他のヒント
でも、あなたが表示された場合に、私は、任意のコンパイラはあなたがお勧め何だろうことを疑うます。
あなたはすべて一つのファイルに非常に簡単なプログラムを使用しています。
あなたはmain.cppにでFooBaseとFooDerivedがfoo.hとFoo.cppで、メインを持っていたことを想像してみてください。 Foo.cppをコンパイルするとき、どのようにプログラム全体でのvtblの必要がないことを知っているようにコンパイラです。それはmain.cppには見ていない。
最後の決意は、
など、手遅れな方法であるとき、リンク時に作られたとはsizeofへのすべての呼び出し(FooDerived)を見つけ、オブジェクトファイルを修正するために複雑になることがありますも、最も近代的な、グローバルに最適化コンパイラは、まだ「独立した翻訳」の原則にこだわっています。この原則によると、すべての翻訳単位は、全体の最終的なプログラムに存在している可能性のある他の翻訳単位についての知識がなくても、独立してコンパイルされます。
あなたは、外部リンケージを持つクラスを宣言すると、、このクラスは、他の翻訳単位で使用することができます。コンパイラは、あなたのクラスは、それらの他の翻訳単位で使用する方法についてのアイデアを持っていません。だから、それは一般的な必要性でそのクラスのかもしれないのすべてのインスタンスの仮想テーブルポインタは、建設の時点で適切に初期化することを前提としています。
あなたの例ではスマートコンパイラは*pFoo
オブジェクトの動的な型がFooDerived
であることを把握することがあります。 FooDerived::bar
発現に応答してpFoo->bar()
関数への直接呼び出しを生成する(仮想テーブルを使用せずに):これは、コンパイラがコードを最適化することを可能にします。しかし、それにもかかわらず、コンパイラは通常、まだ適切に各FooDerived
オブジェクト内の仮想テーブルポインタを初期化する必要があります。
それは可能です。これは、最適化コンパイラが行うことをのポイント-への分析の形の結果です。彼らは、ポインタ変数のデータフロー、および任意の場所にポインタをトレース1つの型のオブジェクトのみにポイントすることができ、それはまさにそのタイプ、(すなわち、コンパイル時に)静的に仮想呼び出しのセマンティクスを実装します。
のコールを生成することができます コンパイラが(もっと人気になって、GCC 4.5でそれを得る)プログラム全体/リンク時の最適化を行っていない限り、他の多くは、言ったように、、それはまだ別のコンパイルをサポートするために、仮想関数のテーブルのいくつかの並べ替えを生成する必要がありますます。