一、淺拷貝和深拷貝
所謂淺拷貝,就是由默認的拷貝構造函數所實現的對數據成員逐一賦值。若類中含有指針類型的數據,這種方式只是簡單的把指針的指向賦值給新成員,但並沒有給新成員分配內存,因此這種方式必然會導致錯誤。爲了解決淺拷貝出現的錯誤,必須顯示的定義一個拷貝構造函數,使之不但複製數據成員,而且爲對象分配各自的內存空間,這就是所謂的深拷貝。
二、淺拷貝
淺拷貝就是由默認的拷貝構造函數所實現的數據成員逐一賦值。通常默認的拷貝構造函數能夠勝任這個工作,但是若類中含有指針類型的數據,這種數據成員逐一賦值的方式將會產生錯誤。
例:
class Student { public: Student( char *name ,int age) //構造函數 { _name = new char [10]; //分配內存 strcpy(_name, name); _age = age; } ~Student() { delete[] _name; //釋放動態內存 } void display() { cout << _name << "--" << _age << endl; } private: char *_name; int _age; }; int main() { Student st1("lisi" , 20); Student st2(st1); //調用默認的拷貝構造函數創建一個新的對象 system( "pause"); return 0; }
程序運行,創建st1時調用構造函數 ,用運算符new從堆上分配一塊空間,並用_name指向這塊內存空間。在執行st2語句時,因爲沒有定義拷貝構造函數,所以調用默認的拷貝構造函數:
Student(Student&st)
{
_name =st._name; //並沒有爲對象st2的數據成員_name分配新的內存空間
_age =st._age;
}
主程序結束時,對象被逐個撤銷,先撤銷對象st2(因爲st2後創建),撤銷前先調用析構函數,用delete運算符釋放所分配的內存空間;撤銷對象st1時,第二次調用析構函數,因爲這時_name所指向的內存空間已經被釋放,企圖對同一塊內存空間釋放兩此,所以這時候程序出錯。
執行過程如圖:
三、深拷貝
爲了解決淺拷貝出現的錯誤,必須顯示的定義一個拷貝構造函數,使之不但能複製數據成員,而且爲指針分配各自的動態內存。
例:
class Student { public: Student( char *name ,int age) //構造函數 { _name = new char [10]; //分配內存 strcpy(_name, name); _age = age; } Student( Student& st ) //自定義的拷貝構造函數 { _name = new char [10]; if (_name != NULL ) { strcpy(_name, st._name); _age = st._age; } } ~Student() { delete[] _name; //釋放動態內存 } void display() { cout << _name << "--" << _age << endl; } private: char *_name; int _age; }; int main() { Student st1("lisi" , 20); Student st2(st1); //調用默認的拷貝構造函數創建一個新的對象 system( "pause"); return 0; }
在執行Student st2(st1)時調用自定義的拷貝構造函數,爲st2._name分配自己的動態內存。程序的執行過程如圖: