賦值運算子過載
阿新 • • 發佈:2019-01-01
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.賦值運算子過載
進行賦值運算子過載實現深拷貝與拷貝建構函式類似,但是也有一些區別。
- 由於目標物件可能引用了以前分配的資料,所以函式應該使用delete[]來釋放記憶體。
- 函式應該避免將物件賦值給自己,否則的話,給物件重新賦值前,釋放記憶體操作可能刪除物件的內容。
- 函式需要返回一個指向呼叫物件的引用。通過返回這樣一個引用,可以實現鏈式操作(即連續賦值),假如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;
}
執行結果: