1. 程式人生 > >effective c++條款12:複製物件時勿忘其每一個成分

effective c++條款12:複製物件時勿忘其每一個成分

我們都知道,如果需要,編譯器會為我們自動生成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函式呼叫。