2012-01-07 138 views
16

這可能是一個明顯的答案或重複的問題。如果是這樣,對不起,我會刪除它。爲什麼複製構造函數不像默認構造函數或析構函數那樣「鏈接」?

爲什麼不鏈接複製構造函數(如默認ctors或dtors),以便在調用派生類的複製構造函數之前調用基類的複製構造函數?使用拷貝構造函數和析構函數時,它們分別在從基到衍生和從基到鏈的鏈中調用。爲什麼複製構造函數不是這種情況?例如,下面的代碼:

class Base { 
public: 
    Base() : basedata(rand()) { } 

    Base(const Base& src) : basedata(src.basedata) { 
     cout << "Base::Base(const Base&)" << endl; 
    } 

    void printdata() { 
     cout << basedata << endl; 
    } 

private: 
    int basedata; 
}; 

class Derived : public Base { 
public: 
    Derived() { } 

    Derived(const Derived& d) { 
     cout << "Derived::Derived(const Derived&)" << endl; 
    } 
}; 


srand(time(0)); 


Derived d1;  // basedata is initialised to rand() thanks to Base::Base() 

d1.printdata(); // prints the random number 

Derived d2 = d1; // basedata is initialised to rand() again from Base::Base() 
       // Derived::Derived(const Derived&) is called but not 
       // Base::Base(const Base&) 

d2.printdata(); // prints a different random number 

拷貝構造函數不會(也不能)真正使對象的副本,因爲Derived::Derived(const Derived&)無法訪問basedata去改變它。

是否有一些基本的東西我錯過了複製構造函數,這樣我的心智模型是不正確的,或者是否存在這種設計的一些神祕(或不神祕)原因?

+0

@ybungalobill已經證明它是可能的,而且很容易。我認爲你的問題是「爲什麼他們不會自動鏈接***?「 – 2012-01-07 21:06:31

+0

@AaronMcDaid是的,這是我的問題,但也已經被回答在 – 2012-01-07 21:07:23

+0

@BenVoigt是的,我想知道爲什麼一個明確寫的不像一個明確寫的構造函數,但這個問題已經回答了一段時間。 – 2012-01-29 23:11:37

回答

17

拷貝構造函數不會(也不能)真正使對象的副本,因爲Derived::Derived(const Derived&)無法訪問pdata去改變它。當然

它可以:

Derived(const Derived& d) 
    : Base(d) 
{ 
    cout << "Derived::Derived(const B&)" << endl; 
} 

如果不指定在初始化列表中基類的構造函數,它的默認構造函數被調用。如果你想要調用默認構造函數以外的構造函數,則必須指定要調用哪個構造函數(以及哪個參數)。

至於爲什麼這是這種情況:爲什麼複製構造函數應該與任何其他構造函數有什麼不同?作爲一個實際問題的例子:

struct Base 
{ 
    Base() { } 
    Base(Base volatile&) { } // (1) 
    Base(Base const&) { } // (2) 
}; 

struct Derived : Base 
{ 
    Derived(Derived&) { } 
}; 

哪個Base拷貝構造函數,你會想到Derived拷貝構造函數調用的?

+0

它似乎是不同的。爲什麼默認構造函數應該與其他構造函數不同? – 2012-01-07 21:00:20

+1

因爲只能有一個默認的構造函數。 – 2012-01-07 21:03:33

+2

默認構造函數與其他構造函數沒有區別。對於所有構造函數,除非在初始化程序列表中明確指定了基類,否則它將被默認構造,就像在初始化程序列表中未指定的所有成員將被默認構建一樣。 – DRH 2012-01-07 21:12:36

3

您可以:

Derived(const Derived& d) : Base(d) { 
    cout << "Derived::Derived(const B&)" << endl; 
} 

這需要的dBase子對象的Base拷貝構造函數。

爲什麼我不知道答案。但通常沒有答案。該委員會只需選擇一個選項或另一個選項。這似乎與其他語言更加一致,例如, Derived(int x)不會自動撥打Base(x)

+0

啊,我忘了這個功能,但爲什麼這不是默認的? – 2012-01-07 20:58:08

+3

@Seth:默認的複製構造函數通過調用它們的拷貝構造函數複製所有子對象,包括基類。 – 2012-01-29 23:10:30

+0

@BenVoigt對不起,我的意思是爲什麼它不是默認的自我複製ctors行爲,而不是爲什麼它不是默認的複製ctor。 – 2012-01-29 23:12:42

2

這是因爲每一個構造默認調用默認的基類的構造:

Derived(const Derived& d) { 
    cout << "Derived::Derived(const B&)" << endl; 
} 

將調用Base()

這是由標準定義的。我喜歡這樣,而不是在類上調用複製構造函數。你當然可以明確地調用它。

相關問題