1. 程式人生 > >賦值運算子過載

賦值運算子過載

0.物件賦值時發生了什麼

C語言中允許把一個結構體賦值給另外一個相同型別的結構體,C++允許把一個物件賦值給另一個同類的物件。這是通過自動為類過載賦值運算子實現的。這種賦值運算子過載函式原型如下。

Class_name & Class_name::operator=(const Class_name &);

它接受一個指向類物件的常引用,並返回一個指向類物件的引用。c++自動提供的這個函式實現了淺拷貝。接著上篇博文的例子來驗證一下。

例1

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
class Man {
    char* name;
    int age;
    public:
        Man(char* name, int age);
        Man();
        Man(const Man & m);
        ~Man();
        void show();
};

Man::Man(char* name, int age)
{
    cout<<"call self-def Constructor"<<endl;
    this->name = new char[strlen(name) + 1];
    strcpy(this->name, name);
    this->age = age;
}
Man::Man()
{
    cout<<"call default Constructor"<<endl;
    this->name = new char[8];
    strcpy(this->name, "Unknown");
    age = -1;
}
Man::~Man()
{
    cout<<"call Destructor"<<endl;
    delete[] name;
}
void Man::show()
{
    // cout<<"name:"<<name<<endl;
    printf("name = %s\n", name);
    cout<<"age:"<<age<<endl;
    printf("str = %p\n",name);
}
Man::Man(const Man & m)
{
    cout<<"call copy Constructor"<<endl;
    this->age = m.age;
    this->name = new char[strlen(m.name) + 1];
    strcpy(this->name, m.name);
}
int main()
{
    Man a = Man((char*)"zhengkang", 26);
    Man b;
    b = a;
    a.show();
    b.show();
    return 0;
}

這個例程的執行結果如下
在這裡插入圖片描述
從執行結果可以看出,a的name指標和b的name指標指向同一片記憶體區域。執行b = a;跟預設的拷貝建構函式一樣,實現的是淺拷貝,那麼淺拷貝存在的問題在這裡同樣存在。釋放a的name指向的記憶體會導致b的name指標指向的記憶體也被釋放掉,這就是需要過載賦值運算子的原因。

1.賦值運算子過載

進行賦值運算子過載實現深拷貝與拷貝建構函式類似,但是也有一些區別。

  1. 由於目標物件可能引用了以前分配的資料,所以函式應該使用delete[]來釋放記憶體。
  2. 函式應該避免將物件賦值給自己,否則的話,給物件重新賦值前,釋放記憶體操作可能刪除物件的內容。
  3. 函式需要返回一個指向呼叫物件的引用。通過返回這樣一個引用,可以實現鏈式操作(即連續賦值),假如a,b,c都是Man物件,那麼可以這樣寫a=b=c;等價於a.operator=(b.operator=(c));

下面,我們過載賦值運算子函式。

例2

Man& Man::operator=(const Man& m)
{
    cout<<"call = overload func"<<endl;
    if (this == &m) //防止a = a這種情況發生
        return *this;
    delete [] name;  //先把原來指向的記憶體去釋放掉
    age = m.age;
    name = new char[strlen(m.name) + 1];
    strcpy(name, m.name);
    return *this;
}

重新執行程式,結果如下:
在這裡插入圖片描述
兩個物件的name指標指向了不同的記憶體區域,互不影響。

2.區分兩條語句

下面兩條語句可能會讓人疑惑,需要區分清楚。

Man b;
b = a;		//呼叫複製運算子過載函式進行物件賦值
Man c = a;   //呼叫拷貝建構函式

例3

int main()
{
    Man a = Man((char*)"zhengkang", 26); //呼叫帶引數的建構函式
    Man b = a; //呼叫拷貝建構函式
    Man c;    //呼叫預設建構函式
    c = a;    //呼叫複製運算子過載函式進行物件賦值
    return 0;
}

執行結果:
在這裡插入圖片描述