第19课 - 对象的构造(下)
1. 特殊的构造函数
(1)无参构造函数
当类中没有定义构造函数时,编译器默认提供一个无参构造函数,并且其函数体为空。
(2)拷贝构造函数
当类中没有定义拷贝构造函数时,编译器默认提供一个拷贝构造函数,简单的进行成员变量的值复制。
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 18 Test(const Test& t) 19 { 20 i = t.i; 21 j = t.j; 22 } 23 24 /* 25 Test() 26 { 27 } 28 */ 29 }; 30 31 int main() 32 { 33 Test t1; 34 35 /* 36 Test t2 = t1; 37 38 printf("t1.i = %d, t1.j = %d ", t1.getI(), t1.getJ()); 39 printf("t2.i = %d, t2.j = %d ", t2.getI(), t2.getJ()); 40 */ 41 42 return 0; 43 }
2. 拷贝构造函数
2.1 拷贝构造函数的意义
(1)兼容 C 语言的初始化方式 int i = 1; int j = i;
(2)初始化行为能够符合预期的逻辑
(3)深拷贝和浅拷贝
① 浅拷贝:拷贝后对象的物理状态相同 【编译器提供的拷贝构造函数只提供浅拷贝】
② 深拷贝:拷贝后对象的逻辑状态相同
1 #include <stdio.h> 2 3 class Test 4 { 5 private: 6 int i; 7 int j; 8 int* p; 9 10 public: 11 int getI(){return i;} 12 13 int getJ(){return j;} 14 15 int* getP(){return p;} 16 17 /* 18 //拷贝构造函数 19 Test(const Test& t) 20 { 21 i = t.i; 22 j = t.j; 23 p = new int; 24 25 *p = *t.p; 26 } 27 */ 28 29 30 //带参构造函数 31 Test(int v) 32 { 33 i = 1; 34 j = 2; 35 p = new int; 36 37 *p = v; 38 } 39 40 ~Test(){delete p;} 41 42 }; 43 44 int main() 45 { 46 Test t1(3); //调用Test(int v); 47 Test t2(t1); //调用Test(const Test& t) 48 49 printf("t1.i = %d, t1.j = %d, *t1.p = %d ", t1.getI(), t1.getJ(), *t1.getP()); 50 printf("t2.i = %d, t2.j = %d, *t2.p = %d ", t2.getI(), t2.getJ(), *t2.getP()); 51 52 return 0; 53 }
2.2 什么时候需要进行深拷贝?
(1)对象中有成员指向了系统中的资源
-
- 成员指向了动态内存空间
- 成员打开了外存中的文件
- 成员使用了系统中的网络端口
- ......
(2)问题分析
★★★一般性原则:自定义拷贝构造函数的时候,必须思考这个拷贝函数是否需要实现深拷贝? 如果不需要,为什么不使用编译器提供的拷贝构造函数?
【编程实验】数组类的改进
1 #ifndef _INTARRAY_H_ 2 #define _INTARRAY_H_ 3 4 class IntArray 5 { 6 private: 7 int m_length; 8 int* m_pointer; 9 10 public: 11 IntArray(int len); 12 IntArray(const IntArray& obj); 13 ~IntArray(); 14 15 int length(); 16 bool get(int index, int& value); 17 bool set(int index, int value); 18 }; 19 20 #endif
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 IntArray::~IntArray() 28 { 29 if(m_pointer) 30 { 31 delete[] m_pointer; 32 } 33 } 34 35 int IntArray::length() 36 { 37 return m_length; 38 } 39 40 bool IntArray::get(int index, int& value) 41 { 42 bool bRet = (0 <= index) && (index <m_length); 43 44 if(bRet) 45 { 46 value = m_pointer[index]; 47 } 48 49 return bRet; 50 } 51 52 bool IntArray::set(int index, int value) 53 { 54 55 bool bRet = (0 <= index) && (index <m_length); 56 57 if(bRet) 58 { 59 m_pointer[index] = value; 60 } 61 62 return bRet; 63 }
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 ", 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 ", i, value); 32 } 33 } 34 return 0; 35 }
3. 小结
(1)C++ 编译器会默认提供构造函数
(2)无参构造函数用于定义对象的默认初始状态
(3)拷贝构造函数在创建对象时拷贝对象的状态
(4)对象的拷贝有浅拷贝和深拷贝两种方式。浅拷贝使得对象的物理状态相同;深拷贝使得对象的逻辑状态相同。