【C++基础】第七十八课:[重载运算与类型转换]赋值运算符

赋值运算符,复合赋值运算符

Posted by x-jeff on July 19, 2023

【C++基础】系列博客为参考《C++ Primer中文版(第5版)》C++11标准)一书,自己所做的读书笔记。
本文为原创文章,未经本人允许,禁止转载。转载请注明出处。

1.赋值运算符

之前已经介绍过拷贝赋值移动赋值运算符,它们可以把类的一个对象赋值给该类的另一个对象。此外,类还可以定义其他赋值运算符以使用别的类型作为右侧运算对象。

举个例子,在拷贝赋值移动赋值运算符之外,标准库vector类还定义了第三种赋值运算符,该运算符接受花括号内的元素列表作为参数。我们能以如下的形式使用该运算符:

1
2
vector<string> v;
v = {"a","an","the"};

同样,也可以把这个运算符添加到StrVec类中:

1
2
3
4
5
class StrVec {
public:
	StrVec &operator=(std::initializer_list<std::string>);
	//其他成员与之前定义一致
};

为了与内置类型的赋值运算符保持一致(也与我们已经定义的拷贝赋值移动赋值运算一致),这个新的赋值运算符将返回其左侧运算对象的引用:

1
2
3
4
5
6
7
8
9
StrVec& StrVec::operator=(initializer_list<string> il)
{
	//alloc_n_copy分配内存空间并从给定范围内拷贝元素
	auto data = alloc_n_copy(il.begin(), il.end());
	free(); //销毁对象中的元素并释放内存空间
	elements = data.first; //更新数据成员使其指向新空间
	first_free = cap = data.second;
	return *this;
}

拷贝赋值移动赋值运算符一样,其他重载的赋值运算符也必须先释放当前内存空间,再创建一片新空间。不同之处是,这个运算符无须检查对象向自身的赋值,这是因为它的形参initializer_list<string>确保il与this所指的不是同一个对象。

我们可以重载赋值运算符。不论形参的类型是什么,赋值运算符都必须定义为成员函数。

1.1.复合赋值运算符

复合赋值运算符不非得是类的成员,不过我们还是倾向于把包括复合赋值在内的所有赋值运算都定义在类的内部。为了与内置类型的复合赋值保持一致,类中的复合赋值运算符也要返回其左侧运算对象的引用。例如,下面是Sales_data类中复合赋值运算符的定义:

1
2
3
4
5
6
7
8
//作为成员的二元运算符:左侧运算对象绑定到隐式的this指针
//假定两个对象表示的是同一本书
Sales_data& Sales_data::operator+=(const Sales_data &rhs)
{
	units_sold += rhs.units_sold;
	revenue += rhs.revenue;
	return *this;
}

赋值运算符必须定义成类的成员,复合赋值运算符通常情况下也应该这样做。这两类运算符都应该返回左侧运算对象的引用。