赋值运算符函数

在上述例子中,当 = 作用于对象时,其实是把它当成一个函数来看待的。在执行 pt1 = pt2; 该语句时,需要调用的是赋值运算符函数。其形式如下:

类名& operator=(const 类名 &)

拷贝构造函数是用一个已经存在的对象初始化一个正在创建的对象,而赋值运算符函数是用一个已经存在的对象赋值另一个已经存在的对象,这是二者本质的区别。

实现赋值运算符的四个基本步骤(重点)

  1. 考虑自赋值问题
  2. 回收左操作数的数据成员原本申请的堆空间
  3. 深拷贝(以及其他的数据成员的赋值)
  4. 返回*this(本对象)
1
2
3
4
5
6
7
8
9
Computer & operator=(const Computer & rhs){
if(this != &rhs){ // 解决自赋值问题,如果是自己赋值自己,字节返回 *this 即可
delete [] _brand; // 回收之前申请的空间,因为 是已经存在的对象嘛,之前的数据已经不再需要
_brand = new char[strlen(rhs._brand)]();
strcpy(_brand,rhs._brand); // 深拷贝
_price = rhs._price;
}
return *this; // 返回当前本对象
}

你可能疑惑为什么 要回收之前的空间再去重新创建,而不能直接复用呢?

如果原来的空间大小不足以满足当前对象的空间大小,应该 delete 之后重新创建。如果原来的空间大小足以满足空间大小,但为了避免数据污染,应该 delete 之后重新创建。

赋值运算符函数的形式探究

思考1-赋值运算符函数的返回必须是一个引用吗?

其实可以不用,但是会造成一次多余的拷贝,增加不必要的开销。

 

思考2-赋值操作符函数的返回类型可以是void吗?

不可以,无法实现连续赋值。就像下面这样:

1
int a = c = b;

如果你的返回值是 void ,那是不可能实现连续赋值的,因此应该返回同类的类型。

 

思考3-赋值操作符函数的参数一定要是引用吗?

其实可以不用,但是会造成一次多余的拷贝,增加不必要的开销。

 

思考4-赋值操作符函数的参数必须是一个 const 引用吗?

是的。可以避免在赋值运算符函数中修改右操作数的内容。还可以解决通过右值属性的对象进行赋值的情况。