C++Primer 第五版 ——《第十四章 》重载运算符 与 类型转换

目录

基本概念

如何调用 非成员函数 和 成员函数的 重载运算符 (491P)

有哪些运算符就不应该被重载 (491P)

重载运算符的 返回类型 应该与 内置版本的返回类型兼容 (492P)

 重载 赋值和 复合赋值运算符 应该返回左侧运算对象的一个引用 (492P)

如果一个类重载了算术运算符或者 位运算符,则最好也提供它们对应的复合赋值运算符。  (492P)

哪些运算符应该重载为成员函数、哪些重载为非成员函数  (492P)

重载运算符和 内置运算符的区别(493P)

重载输出运算符 (494P)

 输出运算符不应该打印 换行符 (494P)

输入输出运算符 必须重载为 非成员函数  (494P)

重载输入运算符  (495P)

在执行输入运算符时可能会发生的错误 (495P)

算术和关系运算符 (497P)

如果类定义了算术运算符,则它一般也会定义一个相应的复合赋值运算符。此时,该类同时定义了算术运算符和对应的复合赋值运算符,那么可以使用复合赋值来实现算术运算符。(497P)

相等运算符 == 、!=(497P)

关系运算符 (498P)

(复合)赋值运算符 ( 499P )

下标运算符 (501P)

递增递减运算符 (502P)

成员访问运算符 (504P)

重载函数调用运算符 & 函数对象 (506P)

lambda 是函数对象 (580P)

表示带捕获的lambda的类 ( 508P)

标准库定义的函数对象 (plus类、modulus类、equal_to类、等等) (509P)

对泛型算法、指针类型的容器 使用标准库函数对象(510P)

可调用对象(函数、函数指针、lambda表达式、bind创建的对象、重载了函数调用运算符的来) 与 标准库 function 类型 (511P)

(显式  / 隐式)类型转换运算符

使用类型转换运算符可能产生意外的结果 (515P)

定义 explicit 的类型转换运算符 (516P)

定义 IO类型向bool的显式转换(546P)

避免有二义性的类型转换 (517P)

 


下面这个程序是本章的示例,我总结了一下:

class Sales_data
{
	// 重载的输入输出运算符一般被声明为友元, 因为它们通常需要读写类的非公有成员
	friend std::ostream &operator<<(std::ostream &os, const Sales_data &item); 
	friend std::istream &operator>>(std::istream &is, Sales_data &item);
	friend bool operator==(const Sales_data &lhs, const Sales_data &rhs);
	
public:
	
	Sales_data operator+=(const Sales_data &rhs);
	std::string isbn() const { return bookNo; }
private:
	double avg_price() const
	{
		return units_sold ? revenue / units_sold : 0;
	}
	std::string bookNo;
	unsigned units_sold = 0;
	double revenue = 0.0;
};
std::ostream &operator<<(std::ostream &os, const Sales_data &item)
{
	os << item.isbn() << " " << item.units_sold << " "
		<< item.revenue << " " << item.avg_price();
	return os;
}
std::istream &operator>>(std::istream &is, Sales_data &item)
{
	double price; // no need to initialize; we'll read into price before we use it
	is >> item.bookNo >> item.units_sold >> price;
	if (is) // check that the inputs succeeded
		item.revenue = item.units_sold * price;
	else
		item = Sales_data(); // input failed: give the object the default state
	return is;
}

//算术运算符通常定义为为非成员函数
Sales_data operator+(const Sales_data &lhs, const Sales_data &rhs)
{
	Sales_data sum = lhs; // copy data members from lhs into sum
	sum += rhs; // add rhs into sum
	return sum;
}
Sales_data Sales_data::operator+=(const Sales_data &rhs)
{
	bookNo += rhs.bookNo;
	units_sold += rhs.units_sold;
	revenue += rhs.revenue;
	return *this;
}

bool operator==(const Sales_data &lhs, const Sales_data &rhs)
{ // 关系运算符通常定义为非成员函数, 如果一个类定义了 operator== , 意味着通常也应该有 operator!=, 反之亦然
	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);
}

基本概念


  • 除了重载 “ 函数调用运算符 operator()  ” 之外, 其他重载运算符不能含有默认实参。
  • 当一个重载的运算符是成员函数时, this绑定到左侧运算对象。成员运算符函数的(显式)形参数量比运算对象的数量少一个。
  • 运算符函数必须是类的成员或至少具有一个类类型的参数 。 这一限制意味着,当应用于内置类型的操作数时,我们不能更改操作符的含义。
// 错误:不能为 int 重新定义新含义
int operator+(int, int);
  • 我们只能重载现有的运算符,而不能创建新的运算符符号。

  • 有四个运算符(+、-、*、&)既是一元运算符也是二元运算符, 这些运算符都能被重载, 从参数的数量我们可以推断到底定义的是哪种运算符。
  • 对于一个重载运算符来说,其具有相同的优先级和结合律与对应的内置运算符保持一致。无论操作数类型如何

如何调用 非成员函数 和 成员函数的 重载运算符 (491P)


有哪些运算符就不应该被重载 (491P)


在本书的第四章介绍过,某些运算符指定了运算对象求值的顺序。因为使用重载的运算符本质上是一次函数调用, 所以这些关于运算对象求值顺序的规则无法应用到重载的运算符上。

所以需要注意: 通常我们不应该重载: 逗号、逻辑与、逻辑或、取地址运算符。

  • 因为逻辑与、逻辑或 运算符的重载版本无法保留求值顺序 或 短路求值属性(因为两个运算对象总是会被求值)。
  • 因为逗号、取地址运算符 ,C++语言已经定义了它们用于类类型对象时的特殊含义。

 


重载运算符的 返回类型 应该与 内置版本的返回类型兼容 (492P)



 重载 赋值和 复合赋值运算符 应该返回左侧运算对象的一个引用 (492P)


如果一个类重载了算术运算符或者 位运算符,则最好也提供它们对应的复合赋值运算符。  (492P)


哪些运算符应该重载为成员函数、哪些重载为非成员函数  (492P)


  • 如果我们想对类对象进行混合运算(比如说类对象和 整数相加),则运算符必须定义成普通的非成员函数。 每个实参都能被转换成形参类型, 但必须至少有一个运算对象是类类型。
  • 当我们把运算符定义为成员函数时, 它的左侧运算对象必须是运算符所属类的一个类类型。

重载运算符和 内置运算符的区别(493P)


不同点

  • 运算符函数如果是类的成员,至少具有一个类类型的参数
  • 重载的运算符不再保留求值顺序等等,例如,逻辑与 和 逻辑或 不再保留 求值顺序 和 短路求值属性,两个运算对象都会被求值

相同点

  • 无论运算对象的类型是什么, 对于一个重载的运算符来说,其结合律 和 优先级与对应的内置版本保持一致
  • 运算对象的个数保持不变

重载输出运算符 (494P)


 输出运算符不应该打印 换行符 (494P)


通常, 输出运算符应该主要负责打印对象的内容而非打印格式化操作, 尤其不应该打印换行符。如果运算符打印了换行符 ,则用户就无法在对象的同一行内接着打印一些描述性的文本了。


输入输出运算符 必须重载为 非成员函数  (494P)


  • 输入和输出运算符一般重载为友元函数,因为它们通常需要读写类的非公有数据成员, 而不能是该类的成员函数。 否则, 它们的左侧运算符对象将是我们该类的一个对象了。

重载输入运算符  (495P)


istream &operator>>(istream &is, Sales_data &item)
{

	double price; 
	is >> item.bookNo >> item.units_sold >> price
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值