2011-09-08 130 views
26

我對構造函數鏈的理解是,當一個類中有多個構造函數(重載構造函數)時,如果其中一個構造函數試圖調用另一個構造函數,那麼這個過程稱爲CON​​STRUCTOR CHAINING,它在C++中不受支持。 最近我碰到這一段就在閱讀在線素材....它是這樣的......C++構造函數鏈

你可能會發現自己在你想寫一個成員函數的情況重新初始化類回默認值。因爲你可能已經有了這樣的構造函數,所以你可能會試圖從你的成員函數中調用構造函數。如前所述,鏈接構造函數調用在C++中是非法的。你可以從你的函數中的構造函數複製代碼,這將工作,但會導致重複的代碼。在這種情況下,最好的解決方案是將代碼從構造函數移動到新函數,並讓構造函數調用您的函數來完成初始化數據的工作。

調用構造函數的成員函數是否也在構造函數鏈中? 請在C++中關注這個主題。

+3

我說不是,這是一個非不合邏輯的文章說,構造函數鏈是非法的,他說,一些任意的成員函數(不一定是一個構造函數)可能會認爲它要調用構造函數來重置後立即價值。但是誰知道,你還沒有引用這篇文章或引用它描述構造函數鏈的地方,所以也許它在別處已經描述過的一些不尋常的意義上使用它。 –

+1

這不是非法的。從成員調用構造函數的效果是創建一個適用於該構造的臨時對象,而不是創建該調用的「this」對象。 –

+1

@Amardeep:同意,這將是更準確的說,構造函數鏈是C++ 03「不可能的」,而不是「非法」。沒有語法來描述這樣做。正如你所說,通過調用構造函數的正常定義與構造函數鏈並不完全相同。 –

回答

17

段落基本上這樣說:

class X 
{ 
    void Init(params) {/*common initing code here*/ } 
    X(params1) { Init(someParams); /*custom code*/ } 
    X(params2) { Init(someOtherParams); /*custom code*/ } 
}; 

不能調用從一個成員函數構造無論是。它可能在你看來,你已經做了,但是這是一個錯覺:

class X 
{ 
public: 
    X(int i):i(i){} 
    void f() 
    { 
     X(3); //this just creates a temprorary - doesn't call the ctor on this instance 
    } 
    int i; 
}; 

int main() 
{ 
    using std::cout; 
    X x(4); 
    cout << x.i << "\n"; //prints 4 
    x.f(); 
    cout << x.i << "\n"; //prints 4 again 
} 
+0

@阿門。你的意思是它第一次被打印4,它實際上是調用構造函數,而第二遍的時候它打印4,雖然我覺得我已經通過調用構造函數(由函數void來達到的結果f()),究竟發生了什麼並不是那樣.. !!!是嗎 ??但我不明白你在上面的代碼中的第一個註釋//這只是創建一個臨時的 - 不在這個實例上調用ctor。你能否更清楚地向我解釋一下? – jsp99

+0

這已經改變了與C + + 11,請參閱http://stackoverflow.com/a/33275207/1915854 –

3

這不是文字所說的。它建議你的構造函數調用一個正常和合法的成員函數。這是爲了避免再次明確地調用ctor並避免在ctor和reset函數之間重複代碼。

Foo::Foo() { 
    Init(); 
} 

void Foo::Reset() { 
    Init(); 
} 

void Foo::Init() { 
    // ... do stuff ... 
} 
+0

這是真的,文字不建議該功能調用構造函數,但是文本顯示「你可能試圖從你的成員函數中調用構造函數,如前所述,鏈接構造函數調用在C++中是非法的」。這表明,通過一些想法的混淆,作者認爲「鏈接構造函數調用」與「從成員函數調用構造函數」有關,無論該文章是否推薦使用該構造函數。當然,可能只是編輯不當。 –

+0

「因爲你可能已經有了這樣的構造函數,所以你可能會試圖從你的成員函數中調用構造函數。」我認爲這意味着應該避免召集建設者的成員函數.. !! – jsp99

+0

@Appy:不一定。例如,在一個名爲'Foo'' * this = Foo();的類中'可能是一個完全合理的重置對象的方法,如果不是最有效的。然後該函數調用構造函數,它不會調用它來構造'this'。 –

0

我不知道,如果它(從調用一個成員函數構造函數)將工作或沒有,但它是一個不好的做法。將初始化代碼移動到新函數是邏輯方式。

基本上是說,不要調用構造函數,除非你構建...

+0

這不只是壞習慣......它不能正常工作。 – Johnsyweb

+0

我同意Johnsyweb。從另一個構造函數調用構造函數只會在其中創建一個臨時局部變量,並在構造函數退出後將其刪除。這個對象不受任何影響。要做到這一點的唯一方法就是重新放置一個貼圖,並重復C++ FAQ,這是一件可怕的事情。 – MasterMastic

1

當我們調用從一個成員函數的構造函數,那麼它會臨時創建的類型的對象。 如果我們在派生類函數中調用,那麼一旦函數超出作用域,所有父構造函數也會被析構函數執行和銷燬。

由於它創建派生的每個類的對象,因此在成員函數中調用構造函數並不是一個好習慣。

15

C++ 11允許構造函數鏈接(部分)。該功能稱爲「delegating constructors」。因此,在C++ 11,你可以做以下

class Foo 
{ 
public: 
    Foo(int a) : Foo() { _a = a; } 
    Foo(char* b) : Foo() { _b = b; } 
    Foo() { _c = 1.5; } 
private: 
    int _a = 0; 
    char* _b = nullptr; 
    double _c; 
}; 

然而,有一個調用另一個構造函數構造不允許初始化任何其他成員的一個嚴重的限制。所以你不能做一個委託構造函數如下:

class Foo 
{ 
public: 
    Foo(int a) : Foo(), _a(a) { } 
    Foo(char* b) : Foo(), _b(b) { } 
    Foo() { _c = 1.5; } 
private: 
    int _a = 0; 
    char* _b = nullptr; 
    double _c; 
}; 

MSVC++ 2013提供了編譯錯誤「C3511:到委託構造函數的調用應是唯一的成員初始化」後者的代碼示例。