學習C++語言的同學都知道,C++中類是有默認的幾個函數的,主要是有四個函數:
四個函數
- 默認構造函數:A(void),無參構造函數
- 拷貝(復制)構造函數:A(const A&a)。用一個對象A去為另一個對象賦值。
- 析構函數:~A(void)。釋放掉A所占用的空間。
- 賦值函數:A &original = const A&a。使用一個對象a直接為另一個對象賦值。
默認的無參構造函數和析構函數不多講,大家都很明白,析構函數不用手動調用,是在類生命期結束的時候系統自動調用的,析構函數主要是釋放分配的空間的(delete和delete[]有類似之處)。
每個類只有一個賦值函數和一個析構函數,但是構造函數卻可以有多個。對於任意的一個類,如果不編寫上述四個函數,C++編譯器會自動生成上述四個函數。那不僅要問了,既然C++編譯器這么智能,為什么我們還要編寫這四個函數呢?
因為這些缺省的拷貝構造函數和賦值函數都是采用“值”操作的方式,而不是“位”操作。這會導致什么問題呢?我們可以想一些,如果類中的成員變量使用了堆空間的時候,就會出現操作的是同一個地址的問題,也就是我們所說的深復制和淺復制的問題。
深復制和淺復制
所謂淺復制,就不是對整個對象的按照位的拷貝,而是僅僅拷貝了數值,就像上面所說的,如果這個類對象中有指針類型(堆空間),那么經過拷貝構造后得到的對象和原來的對象所指向的就是同一塊內存空間,那這算是拷貝么??
深復制就不一樣了,是對整個對象的按照位拷貝,當遇到指針(對空間)類型變量時候,會對整個指針空間拷貝。這樣可以得到兩個完全不同的對象。
拷貝構造函數和賦值函數
那么還有一個問題就是拷貝構造函數和賦值函數到底有什么區別呢?都是值拷貝,那他倆貌似也就一樣吧。拷貝構造函數是在對象被創建時調用的,而賦值函數只能被已經存在了的對象調用。如下式子所示:
String a(“hello”); String b(“world”); String c = a; // 調用了拷貝構造函數,最好寫成c(a);
c = b; // 調用了賦值函數
總結
當類含有動態生成的數據成員,必須自定義析構函數以釋放動態分配的內存,自定義復制構造函數(Copy Structor)和復制賦值操作符(Copy Assignment Operator)實現深復制。