web-dev-qa-db-ja.com

メンバー初期化子は、非静的データメンバーまたは基本クラスを指定しません

このためにGoogleでヒットを見つけるのに苦労しています。

struct a {
    float m_x;
    float m_z;
public:
    a(float x): m_x(x) {}
};

class b : public a {
    b(float z): m_z(z) {}
};

Clang 3.2の場合:

error: member initializer 'm_z' does not name a non-static data member or base class
    b(float z): m_z(z) {}
34
Steven Lu

いいえ、初期化子リストから基本クラスのメンバーを直接初期化することはできません。これは、初期化の順序がこのように進むためです

C++標準n3337§12.6.2/10

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

—まず、最も派生したクラス(1.8)のコンストラクタに対してのみ、仮想基底クラスは、基底クラスの有向非巡回グラフの深さ優先の左から右へのトラバースに現れる順序で初期化されます。 -to-right」は、派生クラスbase-specifier-list内の基本クラスの出現順序です。

次に、直接基底クラスは、base-specifier-listに表示される宣言順に(mem-initializerの順序に関係なく)初期化されます

次に、非静的データメンバーは、クラス定義で宣言された順序で初期化されます(再びmem-initializerの順序に関係なく) 。

最後に、コンストラクター本体の複合ステートメントが実行されます

[注:宣言の順序は、初期化の逆の順序でベースサブオブジェクトとメンバーサブオブジェクトが破棄されることを保証するために義務付けられています。 —終了ノート]

したがって、基本クラスでコンストラクターを指定し(保護することができます)、派生クラスの初期化リストでコンストラクターを使用することができます( 推奨 )またはassign派生クラスctor本体の基本クラスメンバー(異なる動作、異なる効果、および非効率性-デフォルトの初期化された(既に値を持っている)メンバーに割り当てています)。

前者の場合、次のように記述できます。

struct A {
    float m_x;
    float m_z;
    A(){}
protected:
    A(float x): m_x(x) {}
};

class B : public A {
public:
    B(float z) : A(z) {}
    // alternatively
    // B(float z) {
    //     m_x = z;
    // }
};

int main(){
    B b(1);
    return 0;
}
41
4pie0