人生最可悲的事情,莫过于胸怀大志,却又虚度光阴。 ​​​​

《C++ Primer》读书笔记 第14章 操作重载与类型转换

2017.07.22

当运算符作用于类类型的运算对象时,可以通过运算符重载重新定义该运算符的含义。明智地使用运算符重载能令我们的程序更易于编写和阅读。举个例子,因为在Sales_item类中定义了输入、输出和加法运算符,所以可以通过下述形式输出两个Sales_item的和:

cout << item1 + item2;

相反的,由于我们的Sales_data类还没有重载这些运算符,因此它的加法代码显得比较冗长而不清晰:

print(cout,add(data1,data2));

14.1 基本概念

重载的运算符是具有特殊名字的函数;它们的名字由关键字operator和其后要定义的运算符号共同组成。和其他函数一样,重载的运算符也包含返回类型、参数列表以及函数体。

如果一个运算符函数是成员函数,则它的第一个运算对象绑定到隐式的this指针上,因此,成员运算符函数参数数量比运算符的运算对象总数少一个。

对于一个运算符函数来说,它或者是类的成员,或者至少含有一个类类型的参数:

//错误:不能为int冲定义内置的运算符
int operator+(int,int)

我们只能重载已有的运算符,而无权发明新的运算符号。例如,我们不能提供operator**来执行幂操作。

直接调用一个重载的运算符函数

通常情况下,我们将运算符作用域类型正确的实参,从而以这种间接方式“调用”重载的运算符函数。然而,我们也能像调用普通函数一样直接调用运算符函数,先指定函数名字,然后传入数量正确,类型适当的实参:

//一个非成员运算符函数的等价调用
data1 + data2; //普通的表达式
operator+(data1,data2); //等价的函数调用

我们像调用其他成员函数一样调用成员运算符函数。

data1 += data2; //基于“调用”的表达式
data1.operator+=(data2);//对成员运算符函数的等价调用

某些运算符不应该被重载

使用与内置类型一致的含义

赋值和复合赋值运算符

选择作为成员或者非成员

14.2 输入和输出运算符

14.2.1 重载输出运算符<<

std::ostream &operator<<(std::ostream &os,const Sales_data &item)
{
	os << item.isbn() << " " << item.units_sold << " "
		<< item.revenue << " " << item.avg_price();
	return os;
}

14.2.2 重载输入运算符>>

std::istream &operator>>(std::istream &is,Sales_data &item)
{
	double price = 0;
	is >> item.bookNo >> item.units_sold >> price;
	item.revenue = price * item.units_sold;
	return is;
}

14.3 算术和关系运算符

14.3.1 相等运算符

bool operator==(const Sales_data &lhs,const Sales_data &rhs)
{
	return lhs.isbn() == rhs.isbn() &&
			lhs.units_sold == rhs.units_sold && 
			lhs.revenue == rhs.revenue;
}
bool operator!=(const Sales_data &lhs,const Sales_data &rhs)
{
	return !(lhs==rhs);
}

14.3.2 关系运算符

14.2 赋值运算符

14.5 下标运算符

14.6 递增和递减运算符

14.7 成员访问运算符

14.8 函数调用运算符

14.8.1 lambda是函数对象

14.8.2 标准库定义的函数对象

14.8.3 可调用对象与function

14.9 重载、类型转换与运算符

14.9.1 类型转换运算符

14.9.2 避免有二义性的类型转换

14.9.3 函数匹配与重载运算符