3

C++のゴールデンルールの1つは、コンストラクタが正常に完了し、デストラクタが開始されたときにインスタンスのライフタイムが始まることです。仮想コンストラクタイディオム - 虚偽または完全な完全フォールシス

このルールから、考えられる派生インスタンスが有効でないため、未定義の動作につながる可能性があるため、コンストラクタ内で仮想メソッドを呼び出すことはお勧めできません。

C++ FAQ 20.8で説明した仮想コンストラクタの慣用句は、逆のことを示すようです。

私の質問は次のとおりです。

  • そのコンストラクタとデストラクタから呼び出しに対するオブジェクトの寿命を定義するための標準の正確な定義は何ですか?
  • さらに、いわゆる「仮想コンストラクター・アイドーム」は有効ですか?
+2

これは逆のことを示していますか?私はそれに反することは何も見ません... –

答えて

2

コンストラクタの起動時にコンストラクタが属するクラスの型としてオブジェクトが存在します。オブジェクトは矛盾した状態になっている可能性があります(実行はオブジェクトのメソッドの1つにあります)。すなわち、実際にBaseから継承されるDerived型のオブジェクトは、BaseコンストラクタのBaseとして扱われます。いずれのBase::Base()thisBase *として扱われますが、実際のオブジェクトタイプはthisとなります。仮想メソッドを呼び出すことは問題ありません。コンストラクタでは、オブジェクトの実際の型ではなく、コンストラクタのクラスの仮想メソッドが呼び出されます。

最初の質問は「Base class on the initialisation list of a derived class' copy constructor」に記載されています。簡単な答えは、C++ 03の12.7 2-3節でカバーされています。

仮想コンストラクタイディオムは完全に有効です。

+0

更新された答えを見てください。 – outis

+0

@Oxsnarderは、コンストラクタ内で非仮想メソッドを呼び出すのとほぼ同じです。これは、常に人々が行うことです。コンストラクタは、オブジェクトを呼び出す前に呼び出すメソッドが必要とするオブジェクトの状態を保持するかどうかを判断します。メソッドが仮想であるかどうかは、実際にどのメソッド(つまりどのクラス)が実際に呼び出されたか、および/または純粋な仮想メソッド(つまり、現在のクラスに本体がないか、コンストラクター中に基本クラスがありません)。 –

7

私はあなたが2つの別々の(曖昧に関連する)ものを混乱させていると思います。

  1. これは、1つのhere論じた理由のために、コンストラクタ(直接的または間接的に)から仮想関数を呼び出してはならないことは周知です。
  2. よくある質問は、仮想関数からコンストラクタを呼び出すことです。ある意味では#1の反対です。考え方は、いくつかの既存のオブジェクトの動的型に基づいてコンストラクタ(すなわちクラス)を選択することである。