賦值運算子過載(C++實現)詳解

2020-07-16 10:04:41
C++ 允許程式設計師重新定義標準運算子在與類物件一起使用時的工作方式。

正如前面所介紹的,複製建構函式的設計是為了解決包含指標的物件在通過按成員賦值的方式使用同一類的另一個物件的資料進行初始化時出現的問題。類似的問題也會出現在物件賦值中。

例如,建立一個 NumberArray 類,可以讓程式如下定義該類的兩個物件:

NumberArray first(3,10.5);
NumberArray second(5, 20.5);

現在,因為 C++ 允許賦值運算子(=)與類物件一起使用,所以,以下語句也是可以執行的:

first = second;

如果要將第一個物件 first 設定為與第二個物件 second 完全相同的值,此時,C++ 將再次執行按成員複製,從第二個物件複製成員到第一個物件中,這將導致兩個物件中的指標指向同一記憶體。

由於預設的物件賦值遇到了與預設的複製建構函式相同的問題,所以有人可能會認為,程式設計師定義的複製建構函式也可以用來解決預設賦值所導致的問題,但事實並非如此。複製建構函式僅在建立物件並初始化物件時才起作用。特別是,複製建構函式不能在賦值中呼叫。

要理解初始化和賦值之間的區別,可以假設已經建立了 first 物件,然後來看以下語句:

NumberArray second = first; //複製建構函式被呼叫

該語句建立 second 物件,並使用 first 的值初始化它,這是一個初始化語句,它導致複製建構函式被呼叫來執行初始化。但是,以下語句則不一樣:

second = first; //複製建構函式未被呼叫

該語句假定兩個物件都是以前建立的,它僅僅是一個賦值語句,因此不會呼叫建構函式。

為了解決由物件的按成員賦值引起的問題,就需要修改賦值運算子的行為,以便在將其應用於具有指標成員的類的物件時,執行按成員賦值之外的其他操作。換句話說,就是要提供用於該類的物件的賦值運算子的不同版本。所以,這樣做也可以說是要過載賦值運算子。

為給定的類過載賦值運算子的一種方式是定義一個名為 operator= 的運算子函數作為該類的成員函數。例如,要為 NumberArray 類執行此操作,則可以按如下所示編寫該類的宣告:
class NumberArray
{
    private:
        double *aPtr;
        int arraySize;
    public:
        void operator = (const NumberArray & right) ;//過載運算子
        NumberArray(const NumberArray &);
        NumberArray(int size, double value);
        ~NumberArray() { if (arraySize > 0) delete [ ] aPtr; }
        void print() const;
        void setValue(double value);
};
現在先來看一看函數頭或原型,然後再看一看運算子函數本身是如何實現的。函數頭的各個主要部分可以分解如下,如圖 1 所示。

運算符重載 operator= 的函數頭分解
圖 1 運算子過載 operator= 的函數頭分解