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