构造函数
- 无参构造函数
- 默认构造函数
- 有参构造函数
- 带默认值的构造函数 //如果所有的参数都带默认值,那么它就是默认构造函数
- 不带默认值的构造函数
系统自动生成的构造函数(如果自定义了这些构造函数系统将不再自动生成这些构造函数)
- 普通构造函数
- 拷贝构造函数
初始化函数列表只能跟在普通构造函数或拷贝构造函数的后面
拷贝构造函数
1 class Student 2 { 3 public: 4 Student() 5 {cout<<"Student"<<endl;} 6 private: 7 string m_strName; 8 }; 9 int main() 10 { 11 Student stu1; 12 Student stu2=stu1; 13 Student stu3(stu1); 14 return 0; 15 }
当这个程序运行时屏幕上只会打印一行Student,而不是所想的那样打印三行。一个对象的产生会调用一次构造函数,而这里用一个对象去实例化一个新的对象所调用的将会是拷贝构造函数。拷贝函数在定义时基本上与普通的构造函数没什么两样,只是在参数方面有严格的要求,
定义格式:类名(const 类名 &变量名)
例如:上面的程序的拷贝函数的定义为:
1 Student(const Student& stu){...}
拷贝构造函数与普通的构造函数一样
- 如果没有自定义的拷贝构造函数则系统自动生成一个默认的拷贝构造函数
- 当采用直接初始化或复制初始化实例化对象时系统自动调用拷贝构造函数
浅拷贝:只是将数据成员的值进行简单的拷贝
class Array { public: Array(){m_iCount=5;} Array(const Array &arr) { m_iCount=arr.m_iCount; } private: int m_iCount; }; int main() { Array arr1; Array arr2=arr1; return 0; }
什么是深拷贝,请看下面的程序,分析其中的错误。
class Array { public: Array(){m_iCount=5;m_pArr=new int[m_iCount];} Array(const Array &arr) { m_iCount=arr.m_iCount; m_pArr=arr.m_pArr; } private: int m_iCount; int *m_pArr; }; int main() { Array arr1; Array arr2=arr1; return 0; }
arr1.m_pArr与arr2.m_pArr将会指向同一块内存,这样在操作一个对象进行写值得时候会覆盖掉另一个对象的值,更严重的是当我们销毁一个对象的内存时,另一个对象内存也会被销毁,这样就会导致一块内存被销毁两次,如果你觉得没问题那一定是你的脑子有问题,计算机也会提出*,这样崩溃的不止是计算机,还有初学者的自信,因为计算机也会给你报一段晦涩难懂的错误。正确的结果应当是两个对象的指针应当指向不同的内存,拷贝时不该将内存的指针进行拷贝,而应该是将内存中的每一个元素进行拷贝。
深拷贝
我们应该将代码写成一下这种方式
1 class Array 2 { 3 public: 4 Array(){m_iCount=5;m_pArr=new int[m_iCount];} 5 Array(const Array &arr) 6 { 7 m_iCount=arr.m_iCount; 8 m_pArr=new int[m_iCount]; 9 for(int I=0;i<m_iCount;i++) 10 { 11 m_pArr[i]=arr.m_pArr[i]; 12 } 13 } 14 private: 15 int m_iCount; 16 int *m_pArr; 17 };
当对对象进行拷贝时不是做简单的对象的值的拷贝而应该将堆中的数据也进行拷贝,这种拷贝模式叫做深拷贝