8

これは「VTABLEがいつ作成されるか」についてではありません。。むしろ、VPTRをいつ初期化する必要がありますか?コンストラクターの最初/最後ですか、それともコンストラクターの前/後ですか?

A::A () : i(0), j(0)  -->> here ?
{
  -->> here ?
  //...
  -->> here ?
}
4

3 に答える 3

19

仮想呼び出しの機構(通常はvテーブルですが、そうである必要はありません)は、ctor-initializerの実行中、ベースサブオブジェクトの構築後、およびメンバーの構築前にセットアップされます。セクション[class.base.init]の法令:

メンバー関数(仮想メンバー関数、10.3を含む)は、作成中のオブジェクトに対して呼び出すことができます。同様に、構築中のオブジェクトは、typeid演算子(5.2.8)またはdynamic_cast(5.2.7)のオペランドにすることができます。ただし、これらの操作が、基本クラスのすべてのmem-initializersが完了する前に、 ctor-initializer (またはctor -initializerから直接または間接的に呼び出される関数)で実行された場合、操作の結果は未定義です。

実際には、基本サブオブジェクトの構築中に仮想関数機構が存在しますが、基本クラス用に設定されています。セクション[ class.cdtor]は言う:

仮想関数(10.3)を含むメンバー関数は、構築中または破棄中に呼び出すことができます(12.6.2)。クラスの非静的データメンバーの構築中または破棄中を含め、コンストラクタまたはデストラクタから仮想関数が直接または間接的に呼び出され、呼び出しが適用されるオブジェクトがx構築中のオブジェクト(呼び出す)である場合、または破壊の場合、呼び出される関数はコンストラクタまたはデストラクタのクラスの最後のオーバーライドであり、より派生したクラスでオーバーライドする関数ではありません。仮想関数呼び出しが明示的なクラスメンバーアクセス(5.2.5)を使用し、オブジェクト式xがそのオブジェクトの基本クラスサブオブジェクトの完全なオブジェクトまたはその1つを参照しているxが、その基本クラスサブオブジェクトの1つを参照していない場合、動作は未定義です。

于 2011-07-06T05:32:35.870 に答える
3

基本クラスと派生クラスのコンストラクター間で初期化されます。

class Base { Base() { } virtual void f(); };
class Derived { Derived(); virtual void f(); };

これは、rawメモリがBaseオブジェクトに変換されるときに発生します。これは、オブジェクトの構築中にBaseオブジェクトがDerivedオブジェクトに変換されるときに発生します。オブジェクトを破壊するとき、同じことが明らかに逆に起こります。つまり、タイプが変更されるたびに、vtableポインターが変更されます。(標準によれば、vtablesは存在する必要はないと誰かがコメントしていると確信しています。)

于 2011-07-06T05:26:23.823 に答える
0

このmsdnの記事では、詳細について説明しています。

そこにそれは言う:

「そして最終的な答えは...あなたが期待するようにです。それはコンストラクターで起こります。」

そう..A
::A():i(0)、j(0)
{
->>ここに!
// ...
//
}

ただし、クラスAと、Aから派生したクラスA1があるとします。

  • 新しいAオブジェクトを作成すると、vptrはAクラスのコンストラクターの先頭に設定されます。
  • ただし、新しいオブジェクトA1を作成する場合:

「これが、クラスA1のインスタンスを作成するときの一連のイベント全体です。

  1. A1::A1はA::Aを呼び出します
  2. A::AはvtableをAのvtableに設定します
  3. A::Aが実行されて返されます
  4. A1 :: A1は、vtableをA1のvtableに設定します
  5. A1 :: A1が実行され、「
于 2014-03-24T14:20:14.800 に答える