- 操作符重载能够让类这个类型像built-in类型一样自然,我们能够赋予操作符一些意义,使其代码逻辑流畅且自然:

- 对于类而言,操作符重载其实就是函数:
,第一个形参对应第一个操作数,以此类推。 - 当操作符重载函数为类的成员函数时,左操作数隐式为当前对象
this:
- 如果操作符重载函数既不是成员函数,形参类型又不是类类型的话,那么就会和built-in类型的操作符冲突:

- 不是所有的操作符都可以重载,同时我们也无法自创操作符:
,不论操作符的意义如何,其优先级、关联性和语言定义的一致:
- 除了我们间接的调用操作符函数以显得直观外,我们可以显式地调用:
,放轻松,它就是函数。 - 因为操作符重载实际上就是函数调用,所以对于语言规定的一些操作符特性(例如
&&和||的短路特性,以及,?:,&&,||能够保证操作数的计算顺序)都会失效,因此突然让本应该的规则失效,会让用户不适应,综上,不推荐重载这些操作符:
- 对于类而言,重载操作符需要三思而行:
,简单而言,可以认为操作符重载是对built-in 操作符逻辑意义延伸到自定义的类,而不是扭曲操作符本来的意义:
- 至于将操作符重载函数定义成成员函数还是普通函数呢?建议尽可能为成员函数,除了一些对称操作符应该定义为普通函数会更加灵活,此外对于像
<<和>>的流操作的话,就必须定义成普通函数:
,所谓的对称操作符,例如:
- 对于库中的类而言,它们也进行了操作符重载,例如IO库重载了
<<和>>以支持对built-in 类型进行流操作。为了支持自定义类的IO操作,我们必须对其进行重载,简单而言,对于插入操作符而言,其函数签名是:ostream &operator<<(ostream &os, const ClassType &item):
,而抽取操作符的函数签名是istream &operator>>(istream &is, ClassType &item):
,因为我们需要接收用户的输入,所以我们需要做好流的检查以保证接收对象内在状态一致:
- 对于算术操作符和关系操作符,我们应该定义成普通函数以允许操作数的类型转换:
,此外应该
,原因就是快:
- 对于相等操作符
operator==而言,对于一些标准库算法是有必要的:
,同时关系操作符中,像operator<也很受欢迎:
,对于关系操作符而言,最重要的就是不能相互冲突:
,简单理解就是如果我们两个对象都不比对方小的话,那么我们认为两者就是相等的。 - 额外的赋值运算符应该像
copy constructor和assignment operator一样定义为成员函数,同时它们的目的是允许其他类型直接赋值给该类的类型,因为同类型之间的赋值已经被copy constructor和assignment operator包了:
,同时:
- 对于
operator[]而言:
- 关于自增和自减操作符,因为它们改变类内部的状态,应该定义为成员函数。此外它们适合于迭代器类:
,前缀操作的函数签名:
,而后缀操作的函数签名需要和前缀进行区分:
,注意前缀版本返回引用(reference),后缀版本返回值(value)。 - 关于解引用
operator*和箭头->操作符,它们适合迭代器或指针类:
,这里重载的箭头操作符的返回类型:
应该为指针,具体细节很值得细究:
- 因为类可以存储一些状态,所以对于重载了函数调用操作符的类对象(function objects)而言,其比普通函数更加灵活:
,此外一个类内部可以对该操作符就行操作符重载:
,使用场景是该类通常集合标准库里的算法:
- 对于
lambda表达式而言,他就是重载函数调用操作符的匿名类的匿名对象:
,对于带有捕获对象的lambda而言,情况会稍微复杂一些:
,同时其生成的类是否具有copy/move constructor取决于捕获的对象类型:
- 至于是定义
lambda还是函数对象,取决于问题复杂度:
- 五种可调用对象,以及调用签名(函数类型):
,我们可以通过function将具有相同调用签名的函数对象看成是相同类型:
- 进一步地将类这个类型看成自己人,允许类与其他类型进行相互转换:
,至于转换操作符operator type() const的具体要求:
,例如:
,结合测试:
,注意编译器每次只进行一次用户定义的类型转换,但是可以结合标准的类型转换一起使用。每个转换运算都应该返回相应类型的值(value):
- 通常类应该谨慎重载操作符,但是类转换到bool是非常常见的,尽管这可能会发生意想不到的转换:
,为了防止意外情况发生,我们可以使用explicit关键字来防止隐式转换,但是对于那些用条件判断的表达式,编译器会自动使用explicit限定的类型转换进行隐式转换:
,实例:
- 禁止相互甩锅:
,例如两个类相互转换:
,例如一个类定义了多个转换到算术类型的类型转换操作方式:
- 关于转换和重载而言:

- 对于重载函数而言,如果需要不同的用户定义的转换,那么标准定义的转换无法起到解除歧义的作用:

- 如果类类型用于表达式的话,那么该操作符到底是类定义的重载操作符还是built-in版本,我们无法确定:
,就会造成相互重载的局面:










