class A
定義了複製運算符,析構函數和運算符=。 (Rule of Three)規則三和繼承
如果B
從A
繼承:
- 析構函數會被自動調用
- 我需要產業鏈的構造
operator=
......我應該明確地定義它的類B
?
class A
定義了複製運算符,析構函數和運算符=。 (Rule of Three)規則三和繼承
如果B
從A
繼承:
operator=
......我應該明確地定義它的類B
?不,是不必要的。
如果你仔細閱讀的三個規則,你會發現,沒有提到一個基類,決定僅僅就這一類的適當的屬性和行爲。
(Check this example on ideone)
#include <iostream>
struct A {
A(): a(0) {}
A& operator=(A const& rhs) { a = rhs.a; return *this; }
int a;
};
struct B: A { B(): b(0) {} int b; };
int main() {
B foo;
foo.a = 1;
foo.b = 2;
B bar;
bar = foo;
std::cout << bar.a << " " << bar.b << "\n";
}
// Output: 1 2
這實際上是封裝的真正力量。因爲你成功了,使用規則三,在使基類理智的行爲,其派生類不需要知道拷貝構造函數是否由編譯器默認或手動(複雜)實現的,最重要的事情對於一個用戶(並且派生類是一個用戶),是複製構造函數執行復制。
三條法則提醒我們一個實現細節幫助實現正確的語義。像所有的實現細節一樣,它只對這個類的實現者和維護者很重要。
+1我認爲這是一個明確的答案 – sehe
同樣的規則三也適用於派生類。
該規則適用於所有類,您可以將其應用於每個類下的繼承層次結構,與將其應用於單個類相同。
如果class B
需要的三巨頭任何兩個(拷貝構造函數&析構),那麼你需要定義拷貝賦值運算符爲好。
所以它實際上取決於Derived類的成員&您想要的Derived類對象的行爲。
例如:
如果派生類成員包括任何指針的成員,你需要深層副本,然後按三的規則派生類需要重載,爲三巨頭提供自己的實現。
你爲什麼寫'如果你的B班需要任何兩個......大三'?這個規則不是說如果你需要這三個人中的一個**嗎? – nabulke
@nabulke:不錯啊斑點,我實際上意味着,'任何two'的我錯過的了'這的確改變了含義completely.Thanks打字'! –
另請注意,*析構函數*是一個極端情況,您的類可能不需要析構函數,仍然需要* copy-construction *和* assignment *。最簡單的情況是一個持有內存的類,它被認爲是一個智能指針,默認的*析構函數*將完成它所需要的內容,但是您可能仍然希望通過提供深度複製來提供*值語義*。 –
的析構函數將被自動調用
它仍然是更好地界定在派生類B的析構函數,爲了一致性
我需要鏈構造
當然。如果基礎構造函數是默認構造函數,則一致性更好。
operator = ...我應該爲B類明確定義嗎?
是的,是這樣的:
struct A
{
A& operator=(const A & r)
{
// assign all A's member variables
return *this;
}
};
struct B : public A
{
B& operator=(const B & r)
{
A::operator=(r);
// assign all B's member variables
return *this;
}
};
一個很好的演示切片實際上是有用的和使用。 –
@KerrekSB:這裏絕對沒有切片,因爲'A :: operator ='通過const引用接受它的參數。 –
我不同意,如果編譯器要爲您生成正確的操作,那麼您自己生成它們並冒着錯誤是沒有意義的。爲什麼我要定義一個什麼都不做的析構函數?爲什麼在編譯器執行相同的操作時創建一個複製構造函數和賦值?我可以給你一個理由不:*一致性*,如果添加一個新成員到你的類型,編譯器將永遠不會忘記拷貝的領域,但我忘了新成員添加到類型的拷貝構造函數和賦值他們必須手動定義它們。建議:懶惰,只在*需要時才能工作*。 –
阿爾斯說什麼是正確的,但我不知道他回答你的問題。如果你在B中沒有具體的事情,除了你在A的三巨頭中已經做了什麼之外,你也沒有理由爲什麼你應該定義B的三巨頭。
如果您確實需要其中之一,則應該應用三條規則。
這是一個示例代碼和輸出:
#include <iostream>
class A{
int a;
public:
A():a(0){}
A(A const & obj){std::cout << "CC called\n"; a = obj.a;}
A & operator =(A & a){std::cout << "operator= called\n"; return a;}
~A(){std::cout << "A::dtor called\n";}
};
class B: public A{
};
int main(){
B b,v;
b=v;
}
輸出:
operator= called
A::dtor called
A::dtor called
您誤解了問題.OP沒有要求任何代碼,如果基類應用它,S/He會詢問是否派生類需要應用三規則。 –
用C++ 11,它是5(move構造函數)規則 –
@VJo:實際上,你可以利用拷貝構造函數和移動構造函數和定義單個分配新建分配FY操作者接受其參數按值代替確定兩個它的版本。 –