1

相互依存関係を持つ他のオブジェクトを合成するクラスがある場合、(どのように) 構築順序を強制する必要がありますか?

例えば

class Parent
{
    Child1 c1;
    Child2 c2;
};

Child2 のコンストラクターが Child1& を必要とし、c1 を c2 コンストラクターに渡したいとします。

私が次のことをするだけなら...

Parent::Parent()
    : c2(c1)
{
}

... c2 の初期化子が実行されるまでに c1 が構築されない可能性があるため、これは良いことではないでしょうか? それとも、クラス宣言で c1 が c2 の前に来るだけで十分ですか?

または、明示的に c1 コンストラクターを参照する必要があります (それが必要でない場合は、明示的にするためにそうすることをお勧めしますか?)。例えば

class Parent
{
    Child1 c1;
    Child2 c2;
};

Parent::Parent()
    : c1()
    : c2(c1)
{
}
4

5 に答える 5

3

メンバーは、常に宣言された順序で構築されます。あなたが持っている場合:

class Parent
{
    Child1 c1;
    Child2 c2;
};

c1の前に構築されることが保証されていますc2。したがって、 がc2必要な場合Child1&、これは完全に明確に定義されています。

Parent::Parent()
    : c2(c1)
{
}

c1デフォルトで構築され、その後c2、間違いなくすでに構築された で構築されc1ます。

于 2015-10-08T14:43:30.490 に答える
1

C++ では、初期化子リストのメンバーは、リストに配置した順序ではなく、宣言した順序で初期化されます。実際、宣言した順序でメンバーを初期化しないと、g++ は警告を出力します。したがって、メンバーを論理的な順序 (下位レベルから上位レベルのオブジェクト) で宣言するように注意する必要があります。

于 2015-10-08T14:44:18.743 に答える
1

メンバーデータは宣言順に構築されます。c1前に宣言されている場合c2(例のように)、最初に構築されます。

ただし、2 つの例にはわずかな違いがあります。

Parent::Parent()
    // c1 is implicitly default-initialized
    : c2(c1)
{
}

Parent::Parent()
    : c1(), //c1 is value-initialized
      c2(c1)
{
}

が POD 以外のクラス型の場合Child1、この 2 つは同等ですが、そうでない場合は の値が不定になりますc1

これが重要な場合は、 default -initializationとvalue-initializationの違いについて読むことができます。

于 2015-10-08T14:44:35.907 に答える
1

クラスでの宣言の順序だけが重要です。イニシャライザ リストの構築順序はコンパイラによって守られません。実際、この事実について警告する警告を有効にすることができます (イニシャライザ リストの順序 != 有効な構築の順序)。

于 2015-10-08T14:43:44.107 に答える
1

これはすべて効果がありません。メンバー変数は、宣言の順序で構築されます。完全停止。

cppreferenceからの完全な説明は次のとおりです。

リスト内のメンバー初期化子の順序は関係ありません。初期化の実際の順序は次のとおりです。

  1. リスト項目コンストラクターが最も派生したクラス用である場合、仮想基底クラスは、基底クラス宣言の深さ優先の左から右へのトラバーサルで出現する順序で初期化されます (左から右は外観を指します)塩基指定子リスト内)
  2. 次に、このクラスの base-specifier リストに表示されるように、直接基底クラスが左から右の順序で初期化されます。
  3. 次に、非静的データ メンバがクラス定義の宣言順に初期化されます。
  4. 最後に、コンストラクターの本体が実行されます
于 2015-10-08T14:43:06.727 に答える