淺拷貝
所謂的淺拷貝就是調用默認的拷貝構造函數按照字節序對數據成員逐一賦值。
舉例說明:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;
class Student {
public:
Student(const char *_name, int _score);
~Student();
private:
char* name;
int score;
};
Student::Student(const char* _name,int _score)
{
cout << "constructor " << _name << endl;
name = new char[strlen(_name) + 1];
if (name != 0)
{
strcpy(name, _name);
score = _score;
}
}
Student::~Student()
{
cout << "destructor " << name << endl;
name[0] = '\0';
delete[] name;
}
int main()
{
Student stu1("zhang", 87);
Student stu2(stu1);
return 0;
}
程序運行結果:
解析:
程序運行後,創建對象stu1
時,並且調用構造函數爲其進行初始化。用運算符new開闢了一個空間,並用指針name指向了這塊空間。當執行語句Student stu2(stu1);
時,調用默認的拷貝構造函數將對象stu1
的成員變量的值逐一的賦給了對象stu2
。但是因爲沒有開闢新的空間所以對於對象stu2
的成員變量name
來說,它同樣指向了對象stu1
的成員變量name
的空間。如下圖:
當主程序結束時,各個對象依次撤銷。首先撤銷對象stu2
,第一次調用析構函數,執行delete語句,會釋放動態分配的內存空間。然後當撤銷stu1
時,第二次調用析構函數,因爲此時空間已經被釋放,所以第3行會輸出奇怪的東西,因爲此時字符串zhang已經被隨機字符所取代。當再次執行delete語句是時,同樣因爲空間已經被釋放掉,所以會出現二次釋放的情況,這是不被允許的。如下圖:
深拷貝
爲了解決淺拷貝出現的問題,我們必須顯示的定義一個拷貝構造函數,讓他不但要複製數據,而且要開闢一個新的空間,這就是所謂的深拷貝。
修改之後的代碼:
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<string>
using namespace std;
class Student {
public:
Student(const char *_name, int _score);
Student(Student& stu);
~Student();
private:
char* name;
int score;
};
Student::Student(const char* _name, int _score)
{
cout << "constructor " << _name << endl;
name = new char[strlen(_name) + 1];
if (name != 0)
{
strcpy(name, _name);
score = _score;
}
}
Student::Student(Student& stu)
{
cout << "copy constructor " << stu.name << endl;
name = new char[strlen(stu.name) + 1];
if (name != 0)
{
strcpy(name, stu.name);
score = stu.score;
}
}
Student::~Student()
{
cout << "destructor " << name << endl;
name[0] = '\0';
delete[] name;
}
int main()
{
Student stu1("zhang", 87);
Student stu2(stu1);
return 0;
}
運行結果:
解析:
因爲我們自己顯示的定義了一個拷貝構造函數,所以在執行語句Student stu2(stu1);
時,調用自定義的拷貝構造函數,爲stu2
的name
也開闢了一個空間,所以在程序結束時,調用析構函數時,不會出現淺拷貝出現的錯誤。如下圖:
附加小知識
只有當成員變量中有指針類型的數據時,我們才需要自定義拷貝構造函數。