39

次の (簡略化された) 状況を考えてみましょう。

class Foo
{
private:
    int evenA;
    int evenB;
    int evenSum;
public:
    Foo(int a, int b) : evenA(a-(a%2)), evenB(b-(b%2)), evenSum(evenA+evenB)
    {
    }
};

このように Foo をインスタンス化すると:

Foo foo(1,3);

では、evenA は 0、evenB は 2 ですが、evenSum は 2 に初期化されますか?

現在のプラットフォーム (iOS) でこれを試してみましたが、うまくいくようですが、このコードが移植可能かどうかはわかりません。

ご協力いただきありがとうございます!

4

4 に答える 4

42

これ明確に定義されており、移植可能ですが1、エラーが発生しやすい可能性があります。

メンバーは、初期化リストにリストされている順序ではなく、クラス本体で宣言されている順序で初期化されます。そのため、クラス本体を変更すると、このコードは暗黙のうちに失敗する可能性があります (ただし、多くのコンパイラはこれを検出して警告を発します)。


1. C++ 標準の [class.base.init] から:

非委任コンストラクターでは、初期化は次の順序で進行します。

  • まず、最も派生したクラス (1.8) のコンストラクターの場合のみ、仮想基底クラスは、基底クラスの有向非巡回グラフの深さ優先の左から右への走査に現れる順序で初期化されます。 to-right」は、派生クラス base-specifier-list 内の基本クラスの出現順序です。
  • 次に、直接基底クラスは、base-specifier-list に表示される宣言順に初期化されます (mem-initializer の順序に関係なく)。
  • 次に、非静的データ メンバーは、クラス定義で宣言された順序で初期化されます (これも mem-initializer の順序に関係なく)。
  • 最後に、コンストラクター本体の複合ステートメントが実行されます。

(ハイライトは私です。)

次に、標準のこのセクションでは、メンバー変数を使用して他のメンバー変数を初期化する例を示します。

于 2012-05-23T12:57:48.443 に答える
10

はい、すでに構築されている場合に限ります。構築の順序は、コンストラクターの初期化子の順序ではなく、クラス定義の宣言の順序であることを忘れないでください。また、コンパイラは通常、変数が作成される前に変数を使用したかどうかを通知しません。たとえば、クラスの最上位に移動すると、コンストラクターでは、の前に初期化および字句的にevenSum初期化しても、(初期化子が初期化されていないメンバーを使用するため)未定義の動作が発生します。evenAevenBevenSum

于 2012-05-23T13:00:11.977 に答える
8

メンバーは、クラス定義で宣言された順序で初期化されます。イニシャライザ リストがこの順序に従っている限り、問題ありません。

于 2012-05-23T12:57:22.517 に答える
-2

これは、g++ 4.0.3 (現在 6 歳) でもエラーなしでコンパイルされました。

これは、かなり最近のコンパイラで問題なくコンパイルできると確信しています。

于 2012-05-23T12:59:09.387 に答える