1. 兩個特殊的構造函數
-無參構造函數
沒有參數的構造函數
解釋:無參構造函數看似很是簡單,可是它就特別在它是必須存在的。由於咱們要使用一個類的話,就必須建立對象。建立對象必然牽涉到構造函數的調用。
注意:當類中沒有定義構造函數時,編譯器默認提供一個無參構造函數,而且函數體爲空。必定要特別注意,當類中沒有構造函數時,編譯器纔會提供,不然不會提供。
-拷貝構造函數
參數爲const class_name&的構造函數
(判斷一個構造函數是否是拷貝構造函數的依據:一、const 二、當前類對象的引用)只要看到這樣的參數出如今一個構造函數裏面,它必然的就是一個拷貝構造函數了。面試
當類中沒有定義拷貝構造函數時,編譯器默認提供一個拷貝構造函數,簡單的進行成員變量的值複製。數組
1 #include <stdio.h>
2
3 class Test 4 { 5 private: 6 int i; 7 int j; 8 public: 9 int getI() 10 { 11 return i; 12 } 13 int getJ() 14 { 15 return j; 16 } 17 /*Test(const Test& t) 18 { 19 i = t.i; 20 j = t.j; 21 } 22 Test() 23 { 24 }*/
25 }; 26
27 int main() 28 { 29 Test t1; 30 Test t2 = t1; 31
32 printf("t1.i = %d, t1.j = %d\n", t1.getI(), t1.getJ()); 33 printf("t2.i = %d, t2.j = %d\n", t2.getI(), t2.getJ()); 34
35 return 0; 36 }
在上面這個例子中,一旦定義了網絡
Test(const Test& t) { i = t.i; j = t.j; }
那麼Test t1;就會出錯。爲何?
由於找不到一個Test()的構造函數。
問題:不是編譯器會默認提供一個無參構造函數嗎?
必定要注意,編譯器提供默認構造函數的前提,就是類中沒有構造函數,一旦擁有,編譯器就再也不提供。
呈現一個經典面試題,下面的這個類,它裏面有什麼東西?函數
class Tspa
{code
};對象
它裏面至少有一個無參構造函數,是編譯器提供的。blog
2. 拷貝構造函數的意義內存
-兼容C語言的初始化方式
例如:int i =2; int j = i;
Test t1; Test t2 = t1;
-初始化行爲可以符合預期的邏輯資源
-淺拷貝
拷貝後對象的物理狀態相同
-深拷貝
拷貝後對象的邏輯狀態相同
編譯器提供的拷貝構造函數只進行淺拷貝。
1 #include <stdio.h>
2
3 class Test 4 { 5 private: 6 int i; 7 int j; 8 int* p; 9 public: 10 int getI() 11 { 12 return i; 13 } 14 int getJ() 15 { 16 return j; 17 } 18 int* getP() 19 { 20 return p; 21 }30 Test(int v) 31 { 32 i = 1; 33 j = 2; 34 p = new int; 35
36 *p = v; 37 }42 }; 43
44 int main() 45 { 46 Test t1(3); 47 Test t2(t1); 48
49 printf("t1.i = %d, t1.j = %d, *t1.p = %p\n", t1.getI(), t1.getJ(), t1.getP()); 50 printf("t2.i = %d, t2.j = %d, *t2.p = %p\n", t2.getI(), t2.getJ(), t2.getP());54
55 return 0; 56 }
上面的這個程序,編譯會順利經過。而且你會看到一個現象,t1對象的p和t2對象的p指向了同一段堆空間。你是否是想,這是確定的啊。由於我就是用t1初始化t2,這正是我想要的結果。可是根據經驗,p是在堆上生成的,當咱們不用的時候,須要將其釋放掉。以下面的代碼所示:
1 #include <stdio.h>
2
3 class Test 4 { 5 private: 6 int i; 7 int j; 8 int* p; 9 public: 10 int getI() 11 { 12 return i; 13 } 14 int getJ() 15 { 16 return j; 17 } 18 int* getP() 19 { 20 return p; 21 }30 Test(int v) 31 { 32 i = 1; 33 j = 2; 34 p = new int; 35
36 *p = v; 37 } 38 void free() 39 { 40 delete p; 41 } 42 }; 43
44 int main() 45 { 46 Test t1(3); 47 Test t2(t1); 48
49 printf("t1.i = %d, t1.j = %d, *t1.p = %p\n", t1.getI(), t1.getJ(), t1.getP()); 50 printf("t2.i = %d, t2.j = %d, *t2.p = %p\n", t2.getI(), t2.getJ(), t2.getP()); 51
52 t1.free(); 53 t2.free(); 54
55 return 0; 56 }
編譯就會出錯,由於咱們釋放了兩次相同堆空間中的內存。t1中的p和t2中的p指向了同一段堆空間。
如何解決這個問題?
應該手工來提供一個拷貝構造函數
1 #include <stdio.h>
2
3 class Test 4 { 5 private: 6 int i; 7 int j; 8 int* p; 9 public: 10 int getI() 11 { 12 return i; 13 } 14 int getJ() 15 { 16 return j; 17 } 18 int* getP() 19 { 20 return p; 21 } 22 Test(const Test& t) 23 { 24 i = t.i; //首先是值的複製 25 j = t.j; 26 p = new int; 27 28 *p = *t.p; //p的值就不能直接複製了,須要從新到堆空間中申請。申請完以後,將t1對象中p空間中的值拿出來,放到新申請的堆空間中去。 29 } 30 Test(int v) 31 { 32 i = 1; 33 j = 2; 34 p = new int; 35
36 *p = v; 37 } 38 void free() 39 { 40 delete p; 41 } 42 }; 43
44 int main() 45 { 46 Test t1(3); 47 Test t2(t1); 48
49 printf("t1.i = %d, t1.j = %d, *t1.p = %p\n", t1.getI(), t1.getJ(), t1.getP()); 50 printf("t2.i = %d, t2.j = %d, *t2.p = %p\n", t2.getI(), t2.getJ(), t2.getP()); 51
52 t1.free(); 53 t2.free(); 54
55 return 0; 56 }
何時須要進行深拷貝?
-對象中有成員指代了系統中的資源
成員指向了動態內存空間
成員打開了外存中的文件
成員使用了系統中的網絡端口
...
通常性原則
自定義拷貝構造函數,必然須要實現深拷貝
數組類的改進:
IntArray.h
1 #ifndef _INTARRAY_H_ 2 #define _INTARRAY_H_
3
4 class IntArray 5 { 6 private: 7 int m_length; 8 int* m_pointer; 9 public: 10 IntArray(int len); 11 IntArray(const IntArray& obj); 12 int length(); 13 bool get(int index, int& value); 14 bool set(int index ,int value); 15 void free(); 16 }; 17
18 #endif
IntArray.cpp
1 #include "IntArray.h"
2
3 IntArray::IntArray(int len) 4 { 5 m_pointer = new int[len]; 6
7 for(int i=0; i<len; i++) 8 { 9 m_pointer[i] = 0; 10 } 11
12 m_length = len; 13 } 14
15 IntArray::IntArray(const IntArray& obj) 16 { 17 m_length = obj.m_length; 18
19 m_pointer = new int[obj.m_length]; 20
21 for(int i=0; i<obj.m_length; i++) 22 { 23 m_pointer[i] = obj.m_pointer[i]; 24 } 25 } 26
27 int IntArray::length() 28 { 29 return m_length; 30 } 31
32 bool IntArray::get(int index, int& value) 33 { 34 bool ret = (0 <= index) && (index < length()); 35
36 if( ret ) 37 { 38 value = m_pointer[index]; 39 } 40
41 return ret; 42 } 43
44 bool IntArray::set(int index, int value) 45 { 46 bool ret = (0 <= index) && (index < length()); 47
48 if( ret ) 49 { 50 m_pointer[index] = value; 51 } 52
53 return ret; 54 } 55
56 void IntArray::free() 57 { 58 delete[]m_pointer; 59 }
main.cpp
1 #include <stdio.h>
2 #include "IntArray.h"
3
4 int main() 5 { 6 IntArray a(5); 7
8 for(int i=0; i<a.length(); i++) 9 { 10 a.set(i, i + 1); 11 } 12
13 for(int i=0; i<a.length(); i++) 14 { 15 int value = 0; 16
17 if( a.get(i, value) ) 18 { 19 printf("a[%d] = %d\n", i, value); 20 } 21 } 22
23 IntArray b = a; 24
25 for(int i=0; i<b.length(); i++) 26 { 27 int value = 0; 28
29 if( b.get(i, value) ) 30 { 31 printf("b[%d] = %d\n", i, value); 32 } 33 } 34
35 a.free(); 36 b.free(); 37
38 return 0; 39 }