拷貝的兩種方式:淺拷貝、深拷貝
淺拷貝就是對象的數據成員之間的簡單賦值,如果設計了類而沒有提供拷貝構造函數,當用該類的一個對象去給另一個對象賦值是所執行的過程就是淺拷貝。
如:
class A
{
public:
A(int _data) :data(_data){}
A(){}
private:
int data;
};
int main
{
A a(5), b = a;
}
---------------------------------------------------------------
b = a;----就是淺拷貝,執行後b.data = 5;
當數據成員中沒有指針時,淺拷貝是可行的,但當數據成員中有指針時,如果採用簡單的淺拷貝,則兩類中的兩個指針將指向同一個地址,當對象結束時,會調用兩次析構函數,而導致指針懸掛現象(如果一個地方指針既不爲空,也沒有設置爲指向一個已知的對象,這樣的指針稱爲懸掛指針)
深拷貝和淺拷貝的區別就在於深拷貝會在堆內存中另外申請空間來存儲數據,從而也就解決了指針懸掛。
如:
class A
{
public:
A (int _size):size(_size)
{
data = new int[size];
}
A(){};
A(const A& _A):size(_A.size)
{
data = new int [size];
}
~A()
{
delete[] data;
}
private:
int *data;
int size;
};
int main()
{
A a(5), b = a;
}
例程(淺拷貝):--轉載
class Cperson
{
public:
Cperson(int age);
void Print(void);
private:
int m_age;
};
Cperson::Cperson(int age):m_age(age)
{
}
void Cperson::Print(void)
{
cout << "My age is " << m_age << endl;
}
void main(void)
{
Cperson Tom(10);
Tom.Print();
Cperson Jim(Tom);
Jim.Print();
}
運行結果:
My age is 10
My age is 10
結果分析:
對應語句Cperson Jim(Tom) 編譯器將自動生成一個默認的拷貝構造函數。
錯誤的淺拷貝:
class Cperson
{
public:
Cperson(int age,char *name);
~Cperson();
void Print(void);
private:
int m_age;
char *m_name;
};
Cperson::Cperson(int age, char *name)
{
m_name = new char[strlen(name) + 1 ];
if(m_name != NULL)
strcpy(m_name, name);
m_age = age;
cout << m_name << endl;
}
Cperson::~Cperson()
{
cout << " 析構:" << m_name << endl;
if(m_name != NULL)
delete m_name;
}
void Cperson::Print(void)
{
cout << "My age is " << m_age << " My name is " << m_name << endl;
}
void main(void )
{
Cperson Tom(10, "Tom");
Tom.Print();
Cperson Jim(Tom);
Jim.Print();
}
程序出現錯誤:
執行語句Cperson Tom(10, "Tom") 時,用new動態開闢了一段內存,用來存放"Tom"
執行Cperson Jim(Tom) 時只是將Tom 的成員Tom.m_age, Tom.m_name 賦值給了Jim 相應的成員。
此時 Tom.m_name Jim.m_name 指向同一內存空間, 系統並沒有給Jim.m_name開闢相應的內存空間。
執行完Jim.Print()後,開始執行析構函數,析構函數的執行順序和構造函數的執行順序相反,即先執行Jim的析構函數,釋放掉Jim.m_name 的內存空間。析構Tom是空間就會出問題。
深拷貝:
class Cperson
{
public:
Cperson(int age, char *name);
Cperson(Cperson& per);
~Cperson();
void Print(void);
private:
int m_age;
char *m_name;
};
Cperson::Cperson(int age, char *name)
{
m_name = new char[strlen(name) + 1];
if(m_name != NULL)
strcpy(m_name, name);
m_age = age;
}
Cperson::Cperson(Cperson& per)
{
m_name = new char[strlen(per.m_name) + 1];
if(m_name != NULL)
strcpy(m_name, per.m_name);
m_age = per.m_age;
}
Cperson::~Cperson()
{
delete m_name;
}
void Cperson::Print()
{
cout << "My age is " << m_age << "My name is "<< m_name << endl;
}
void main(void)
{
Cperson Tom(10, "Tom");
Tom.Print();
Cperson Jim(Tom);
Cperson.Print();
}
自定義拷貝構造函數後,就沒有問題了, 在實際中應儘量避免淺拷貝。