C++編譯器產生的預設函數
話題引入:
對象的賦值與複製是如何進行的?他們的區別是什嗎?如果一個空的自訂類型能否執行這些操作?
對象賦值:通過“ =
”運算子多載
User a(10),b;
b = a;
對象複製:調用拷貝建構函式
User b;
User a(b);
或者
User a = b; //相當於User a(b);
也是調用拷貝建構函式
二者的區別:賦值是對一個已經存在的對象進行賦值(已經實現定義了被賦值的對象),而複製是從無到有建立一個新的對象,並使它與已有的對象相同。
淺複製與深複製:若對象中有指標成員,在複製時,只會將該指標成員的地址複製給建立立的對象,因此,兩個對象中的指標成員都指向了同一塊記憶體地區,在釋放時會出現重複釋放的問題。需要手動定義拷貝建構函式,在建構函式中將為指標變數分配新的記憶體,是不同對象的指標成員指向不同的記憶體地區。
用到拷貝建構函式的三種情況:
1、需要建立一個新對象,並用另一個同類對象對其進行初始化
2、函數的參數為類的對象時,在調用函數時需要建立一個實參的拷貝,按實參複製一個形參,系統是通過調用拷貝建構函式實現的
3、函數的傳回值是類的對象:函數調用結束時,需要將函數中的對象複製一個臨時對象,並傳給該函數的調用處。
User getUser(){ User temp; return temp;}int main(){ User user = getUser();//調用getUser();}
getUser()函數調用結束時,getUser中建立的對象temp的生命週期結束(即將銷毀),所以不是將temp帶回main,而是在執行return語句時,調用User類的拷貝建構函式,按temp拷貝一個新的、對象,然後將它賦值給user.
編譯器提供的預設函數:
以上提到了對象的拷貝構造和賦值運算,如果是自訂類型想進行這些操作,還需要額外的函數定義嗎?答案是:如果沒有特殊要求則不需要,編譯器已經給我們提供了預設實現。只是需要注意的是這些預設實現是按位複製的淺複製方式。
定義一個空的C++類,例如
class Empty{}
一個空的class在C++編譯器處理過後就不再為空白,編譯器會自動地為我們聲明一些member function,一般編譯過去就相當於
class Empty{public:Empty(); // 預設建構函式Empty( const Empty& ); // 拷貝建構函式~Empty(); // 解構函式Empty& operator=( const Empty& ); // 賦值運算子Empty* operator&(); // 取址運算子const Empty* operator&() const; // 取址運算子 const};
下面給出一個完整實現這些函數的類型定義樣本:
class Student{public:Student(); //建構函式~Student(); //解構函式Student( const Student& stu ); //拷貝建構函式Student& operator=( const Student& stu); //賦值運算子bool operator==(const Student& stu) const; //==運算子多載public:char Name[10];int Age;};//建構函式Student::Student(){TRACE("Student的建構函式\r\n");}//解構函式Student::~Student(){TRACE("Student的解構函式\r\n");}//拷貝建構函式Student::Student( const Student& stu){TRACE("Student的複製建構函式\r\n");sprintf(Name, stu.Name);Age = stu.Age;}//賦值運算子Student& Student::operator=( const Student& stu){TRACE("Student的賦值運算子\r\n");//此處應該先釋放該對象的成員變數指向原有記憶體(該類型不涉及)//...sprintf(Name, stu.Name);Age = stu.Age;return *this;}bool Student::operator==( const Student& stu) const{TRACE("==運算子\r\n");return strcmp(Name, stu.Name) == 0 && Age==stu.Age;}