親子関係を持つ2つのクラス(Parent
クラスは "has-a" Child
クラス)があり、Child
クラスにはParent
へのポインターがあります。次のように、子の構築時に親ポインタを初期化すると便利です。
class Child;
class Parent;
class Child
{
public:
Child (Parent* parent_ptr_) : parent_ptr(parent_ptr_) {};
private:
Parent* parent_ptr;
};
class Parent
{
public:
Parent() : child(this) {};
private:
Child child;
}
今、私は人々が初期化リストでthis
を使用しないことを推奨していることを知っています、そして C++ FAQ はコンパイラ警告を受け取るつもりです(BTW、VS2010では警告を受けません)が、私は本当にこのようにすると、Parent
のコンストラクターでいくつかのセット関数を呼び出すことができます。私の質問は:
this
オブジェクトが作成されるときに、親Child
ポインターは明確に定義されていますか?おかげで、
ボアズ
編集:Timboに感謝します。それは確かに 重複 です(ええと、私は同じクラス名を選択しさえしました)。それでは、いくつかの付加価値を得ましょう:参照はどうですか?以下を行うことは可能/安全ですか? :
class Child
{
public:
Child (Parent& parnet_ptr_) : parent_ptr(parent_ptr_) {};
private:
Parent* parent_ptr;
};
class Parent
{
public:
Parent() : child(*this) {};
private:
Child child;
}
はい。 this
ポインターを初期化リストで使用しても安全です。初期化されていないメンバーまたは仮想関数に直接または間接的にアクセスするために使用されていない限り )、オブジェクトがまだ完全に構築されていないため。オブジェクトchild
は、後で使用するためにthis
のParent
ポインターを格納できます!
親this
ポインター(「ポインター用語」)isは明確に定義されています(そうでない場合、親コンストラクターはどのインスタンスで動作しているかをどのようにして知るのでしょうか)。
Child
オブジェクトの後に宣言されたフィールドはまだ初期化されていません。したがって、一般的に親オブジェクトはまだ一貫性のない状態です。子オブジェクトが親オブジェクトの構築で実行するすべてのこと、半分構築されたオブジェクトで実行されること、およびこれは一般に良いことではありません(たとえば、「通常の」メソッドを呼び出す場合-これは、オブジェクトは完全に構築されています-「不可能な」コードパスに入る可能性があります)。
それでも、子オブジェクトがそのコンストラクターで親ポインターを使用してすべてそれを保存して後で使用できるようにする場合(=>実際に構築されるとき)、問題はありません。
afterParent
オブジェクトが完全に構築されるまでポインタを逆参照しない限り、動作は明確に定義されています(@Sergeyが以下のコメントで言っているように、構築されるオブジェクトは実際にはParent
から派生しているため、そのコンストラクタのallが完了している必要があります)。