effective c++條款12:複製物件時勿忘其每一個成分
阿新 • • 發佈:2018-12-15
我們都知道,如果需要,編譯器會為我們自動生成copying函式(拷貝構造與copy assignment操作符)。如果我們想覆蓋它們,只需要自己實現copying函式即可;
但是!!!!!!!
編譯器不樂意了o(╥﹏╥)o:好傢伙,既然你不相信我,那你出了某些錯我可別怪我不提醒你!!!
什麼錯誤呢???
錯誤一:
假設有這麼一個類:
class MyClass { private: int SomeValue; public: MyClass(){} ~MyClass(){} MyClass(const MyClass &Temp):SomeValue(Temp.SomeValue){} MyClass operator =(const MyClass &Temp) { SomeValue = Temp.SomeValue; } };
當你使用拷貝構造時,一切都進行的很順利,直到你添加了一個成員變數:
class MyClass { private: int SomeValue; std::string name;//新來的 public: MyClass(){} ~MyClass(){} MyClass(const MyClass &Temp):SomeValue(Temp.SomeValue){} MyClass operator =(const MyClass &Temp) { SomeValue = Temp.SomeValue; } };
這時,如果你沒有將所有的copying函式做修改,將name成員加上去,那麼當你使用copying函式時,就會遺漏一個成員沒有被複制,而編譯器並不會告訴你╭(╯^╰)╮。。。。
錯誤二:
如果含有自定義copying函式的son類去繼承father類,
class Father { public: int SomeValue; public: Father(){}//建構函式 ~Father(){} Father(const Father &Temp):SomeValue(Temp.SomeValue){} Father &operator=(const Father &Temp) { SomeValue = Temp.SomeValue; return *this; } }; class Son: public Father { public: std::string SomeString; public: Son(){} ~Son(){} Son(const Son &Temp):SomeString(Temp.SomeString){} Son &operator=(const Son &Temp) { SomeString = Temp.SomeString ; return *this; } };
那麼當Son類物件呼叫拷貝建構函式時,並沒有繼續呼叫Father類中相應的拷貝建構函式,而僅僅是用Father類中的default建構函式將Son類物件中的父類成員初始化。
如果呼叫copy assignment操作符,那麼Son類中Father類成員保持不變,即不會被預設構造初始化,也不會被複制。
#include <iostream>
#include <string>
using namespace std;
class Father
{
public:
int SomeValue;
public:
Father(){}//建構函式
~Father(){}
Father(const Father &Temp):SomeValue(Temp.SomeValue){}
Father &operator=(const Father &Temp)
{
SomeValue = Temp.SomeValue;
return *this;
}
};
class Son: public Father
{
public:
std::string SomeString;
public:
Son(){}
~Son(){}
Son(const Son &Temp):SomeString(Temp.SomeString){}
Son &operator=(const Son &Temp)
{
SomeString = Temp.SomeString ;
return *this;
}
};
int main()
{
Son MySonA;
MySonA.SomeString = "哈哈";
MySonA.SomeValue = 1;
Son MySonB(MySonA);
cout << "MySonB父類成員SomeValue沒有被複制" << endl;
cout <<"類A: " << MySonA.SomeString << " " << MySonA.SomeValue << endl;
cout <<"類B: " << MySonB.SomeString << " " << MySonB.SomeValue << endl;
return 0;
}
然而編譯器依舊不會提醒你。。。。。。。。
注意,如果是編譯器預設的copying函式,那麼它們會自動呼叫相應父類copying函式。
解決方法:
在Son類的copying函式中手動呼叫Father類的copying函式:
class Father
{
public:
int SomeValue;
public:
Father(){}
~Father(){}
Father(const Father &Temp):SomeValue(Temp.SomeValue){}
Father &operator=(const Father &Temp)
{
SomeValue = Temp.SomeValue;
return *this;
}
};
class Son: public Father
{
public:
std::string SomeString;
public:
Son(){}
~Son(){}
Son(const Son &Temp):Father(Temp), /*新增的程式碼*/SomeString(Temp.SomeString){}
Son &operator=(const Son &Temp)
{
Father::operator=(Temp);//新增的程式碼
SomeString = Temp.SomeString ;
return *this;
}
};
最後
提醒:即使兩個copying函式的程式碼重複率較高,不要試圖用其中一個去呼叫另外一個來簡化程式碼。
解決方法:實現一個private函式,包含相同的程式碼,供兩個copying函式呼叫。