1.複製控製成員是指:複製建構函式、賦值操作符函數、解構函式
2.關於複製建構函式,見:複製建構函式總結
3.如果沒有自己的賦值操作符函數,編譯器會提供一個。
賦值操作符也是依次複製每個非static成員,也是淺層複製。
賦值操作符與複製構造的區別,只是不用為對象開闢新空間。
4.析構對象的順序,是建立對象的逆序,也即聲明次序的逆序
例:
class A{int x;public:A(int i){x = i;cout<<"construct A "<<i<<endl;}~A(){cout<<"delete A "<<x<<endl;}};class B{A a;A b;A c;public:B():c(3),b(2),a(1){cout<<"construct B"<<endl;}~B(){cout<<"delete B"<<endl;}};int main(){B b;return 0;}
輸出結果:
construct A 1
construct A 2
construct A 3
construct B
delete B
delete A 3
delete A 2
delete A 1
這裡特意讓初始化列表的順序不同,可以看出構造與析構的順序與初始化列表無關,只與聲明順序有關
5.和其它函數不同的是,即使定義了自己的解構函式,還是會執行預設的解構函式
先運行自己的解構函式,再運行預設的解構函式
6.在複製控制函數中,複製時只複製內容,這種複製稱為淺層複製
比如複製指標,只複製指標中的地址,不複製指標指向的內容。
當類中有指標成員時,淺層複製會出錯。需要定義自己的深層複製
如果需要定義自己的解構函式,就肯定需要定義自己的所有這也三個控製成員函數
7.定義自己的控製成員函數
class A{int val;int *ptr;public:/*建構函式ptr(new int(p)):建立一個int,int的內容與p相同,ptr指向該int*/A(const int &p, int i):ptr(new int(p)),val(i){}/*複製建構函式*orig.ptr:取指標orig.ptr指向的內容ptr(new int(*orig.ptr)):建立一個int,int的內容與*orig.ptr相同,ptr指向該int*/A(const A &orig):ptr(new int(*orig.ptr)),val(orig.val){}/*賦值操作符不需要開闢空間*/A& operator=(const A &orig){/*是函數內容的意思rig.ptr指向的內容賦給ptr指向的內容*/*ptr = *orig.ptr;val = orig.val;return *this;}//解構函式~A(){delete ptr;}};
需要注意的是,在本例中,this對象可以訪問orig對象的私人成員。
對於私人的定義是這樣的:只允許類的建立者(在這裡是this)和該類的成員函數可以訪問
我理解的可以訪問是指可以訪問建立者的私人成員。
為什麼在本例中this對象可以訪問orig對象的私人成員?求解釋
8.如果類中有指標成員,複製控制函數一定要自己寫。
有時候,複製控制的應用不是很明顯,容易被忽略。
所以發現類中有指標成員時,一定要仔細分析類的使用,不能忽視任意一處可能的複製控制的使用
最保險的方法就是,只要看到類中有指標成員,就自己寫複製控制