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 }