1 class A 2 { 3 public: 4 A(int x) : _x(x){} 5 ~A(){} 6 public: 7 int _x; //方便测试改为public 8 public: 9 A(const A& a){_x = a._x;} 10 A &operator=(const A& a); 11 }; 12 13 A &A::operator=(const A &a) 14 { 15 if(this == &a) return *this; 16 17 _x = a._x; 18 19 return *this; 20 }
先看上面一段简单代码,写的很简单的浅拷贝,之前对于复制构造函数存在相当多的不理解。
(1)不理解为什么参数要写成引用,后来看了剑指offer后,上面说如果不写成引用,调用A的复制构造函数时参数会copy,此时会调用自己本身的复制构造函数,所以一层层的调用,直到栈溢出。
(2)赋值运算符函数为什么要返回实例自身的引用,主要是为了支持如下功能:
A a(10);
A b(20);
A c(30);
a = b = c;
如果返回的是void,就无法支持a = b = c,至于为什么返回的是引用,请看下面的式子:
如果赋值运算符函数为这样: A operator=(const A& a);
(a = b) = c;
结果a._x 等于多少? 结果是20,而不是30,因为返回的不是引用,只是一个临时的对象,修改的也是那个临时对象的值,而不是对象a的 值。
(3)赋值运算符函数内部为什么是const 并且是引用,因为赋值运算符函数不会改变传入实例的状态,因此需要加上const,至于为什么是引用,则是因为如果不是引用,参数会被复制一份副本,从而会调用一次复制构造函数,会增加函数调用的开销。