C++ 复制构造函数
——复制构造函数用于将一个对象的值复制到新创建的对象中,用于初始化过程中(包括按值传递参数),而不是常规的赋值过程中
原型:
Class_name(const Class_name &)
何时调用:
- 新建一个对象并将其初始化为同类现有对象时,复制构造函数都将被调用
StringBad ditto(motto); // calls StringBad(const StringBad &) StringBad metoo = motto; // calls StringBad(const StringBad &) StringBad also = StringBad(motto); // calls StringBad(const StringBad &) StringBad * pStringBad = new StringBad(motto) // calls StringBad(const StringBad &)
中间两种声明可能会使用复制构造函数直接创建metoo和also,也可能使用复制构造函数生成一个临时对象,然后将临时对象的内容赋给metoo和also,这取决于具体的实现
- 每当生成了对象副本时,编译器都将使用复制构造函数。具体地说按值传递和返回对象时,都将调用复制构造函数(按值传递意味着创建原始变量的一个副本)。
- 由于按值传递对象时将调用复制构造函数,因此应该按引用传递对象。这样可以节省调用构造函数的时间以及存储新对象的空间
功能:
——默认的复制构造函数逐个复制非静态成员(成员复制也称为浅复制),复制的是成员的值
StringBad sailor = sports; //等效于 StringBad sailor; sailor.str = sports.str; sailor.len = sports.len;
只是由于私有成员是无法访问的,因此后面的代码不能通过编译
静态对象不受影响,因为它们属于整个类,而不是各个对象
默认复制构造函数的问题:
一:
默认的复制构造函数不说明其行为(全盘复制),如果需要在构造函数中修改类静态数据成员,这时就会发生错误
解决办法:提供一个显示复制构造函数
StringBad::StringBad(const String &s) { num_strings++; // static int num_strings声明在类中 ... // imported stuff to go here }
如果类中包含这样的静态数据成员,即其值将在新对象被创建时发生变化,则应该提供一个显示复制构造函数
二:
隐式复制构造函数的浅复制(复制指针)导致的内存问题
- 新对象可能修改指针指向的内存
- 新对象若走完生命周期将会调用析构函数释放指针指向的内存,但当原对象也调用析构函数时,由于该段内存已被释放,这将导致不确定的、可能有害的结果,另一个症状是试图释放内存两次可能导致程序异常终止
解决办法:定义一个显示复制构造函数,进行深度复制
StringBad::StringBad(const StringBad &st) { num_strings++; // handle static member update len = st.len; // same length str = new char [len + 1]; // allot space std::strcpy(str, st.str); // copy string to new location ... }
复制字符串并将副本的地址赋给str成员
如果类中包含了使用new初始化的指针成员,应当定义一个复制构造函数,以复制指向的数据,而不是指针,这被称为深度复制。复制的另一种形式(成员复制或浅复制)只是复制指针值。浅复制仅浅浅地复制指针信息,而不会深入“挖掘”以复制指针引用地结构