2013-08-28 35 views
21

我很難在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) {} 
}; 

在鐺3.2:

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

爲什麼?我還沒有製造出「邪惡的繼承鑽石」。 @Andrey在這個問題上接受的答案說要做出一個基本的決定。我有一個......哦。我想我需要調用基類ctor,而不是成員ctor。好。 –

+0

@WhozCraig:即使它是一個虛擬基礎,它仍然不會讓你初始化*間接*成員。虛擬繼承可能需要初始化間接*基礎*,但不是成員。 – AnT

+1

@Steven Lu:接受的答案是'a :: m_z'只能從'a'的構造函數初始化列表中初始化。它不能在'b'的構造函數初始值設定項列表中提及(就像在你的代碼中一樣)。該語言不允許。這纔是重點。即你必須爲'm_z'特別添加另外一個參數到'a'的構造函數中(就像你爲'm_x'所做的那樣),並通過該構造函數從'b'傳遞初始值。順便說一句,在你的代碼中,你必須從'b'的構造函數中引用'a'的構造函數。否則,它不會編譯,因爲'a'中沒有默認的構造函數。 – AnT

回答

26

不,你不能從初始化直接初始化列表基類成員。這是因爲

C++標準n3337 § 12.6.2/10

在非委託構造,在 初始化進行下列順序以這種方式初始化收益順序:

- 首先,並且僅對於派生類(1.8)的構造函數最多,虛擬基類按照 的順序進行初始化,它們出現在基c的非循環圖的深度優先從左到右的遍歷中其中「從左到右」是 的次序出現在派生類 base-specifier-list中的基類。

- 然後,如它們出現在基地說明符列表 (不管MEM-初始化的順序的)直接基類在 聲明的順序初始化

- 然後,非靜態 數據成員以他們在 類定義中聲明(再次不管 MEM-初始化的順序)的順序進行初始化

- 最後, 構造函數體的複合聲明執行

[注意:聲明順序要求確保基址和 成員子對象以 初始化的相反順序銷燬。 - 注完]

所以,你可以指定一個基類(可以保護)構造和使用一個派生類(should be preferred)的初始化列表,或者您可以分配基類成員在派生類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; 
} 
相關問題