第19课构造函数(下)

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 }
相关文章
相关标签/搜索