クラスは仮想メソッドを宣言する場合があると、コンパイラはvptrを使用する必要はありませんか?

StackOverflow https://stackoverflow.com/questions/2336107

  •  22-09-2019
  •  | 
  •  

質問

コンパイラは、オブジェクトのタイプは、仮想メソッドを持つクラスであってもインスタンス化されたオブジェクトにvptrを割り当てる必要はありません。

の可能な最適化がある場合は、

私は思っていました たとえば、考えてみます。

#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でそれを得る)プログラム全体/リンク時の最適化を行っていない限り、他の多くは、言ったように、

、それはまだ別のコンパイルをサポートするために、仮想関数のテーブルのいくつかの並べ替えを生成する必要がありますます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top