《C++Primer》第十四章:重载运算和类型转换

  1. 逻辑与、逻辑或、逗号运算符的运算对象求值顺序不能保留,&&和||符号的短路属性也会消失,因此不建议重载他们,这会使得重载后的对象和我们平常熟悉的计算规则不同。另外取地址也不建议被重载。
  2. 重载输出运算符尽量不要控制格式,比如不应该打印换行符。
  3. 输入输出运算符一定是非成员函数,如果是成员函数那么第一个参数会默认是对象自身,然而输入输出运算符要求第一个参数是流对象的引用。由于需要读取对象成员,因此也应该是友元,除非只打印公有成员。
  4. 通常情况下把算术和关系运算符定义成非成员函数以允许对左侧或右侧的对象进行转换,另外不需要改变他们所以形参都是常量引用。
  5. 定义算术运算符后通常也要定义对应的符合赋值符,最好的方法就是使用符合赋值来定义算术运算符。同理,相等运算符和不等运算符也应该一起实现,具体的工作写在其中一个里面就可以。
  6. 定义关系比较运算符比如大于小于时,要小心和等于运算符的兼容性,比如a<b时,一定要a!=b,当a!=b时,大于小于比较一定要有一个为真。
  7. 下标运算的返回值通常是元素的引用,这使得下标的返回值的改变可以体现在原对象上,即可以成为左值。另外下边运算通常有常量和非常量两种版本的重载,这使得常量对象使用下表操作时不会改变自身。
  8. 如果类定义了调用运算符,则该类的对象被称为函数对象,函数对象常常作为泛型算法的实参。而我们普遍的做法是在泛型算法中传入一个lambda表达式,实际上编译器将lambda表达式翻译为一个未命名类的未命名对象,该对象有重载的调用运算符。该调用运算符是const的,除非加上mutable修饰lambda表达式。
  9. 没有捕获列表的lambda表达式形成的匿名类中没有数据成员,只需要一个重载的调用运算符就可以。通过引用捕获变量时也是这样。但是如果有值捕获的捕获列表,实际上该类就可以理解为有私有的数据成员,并且有对应的构造函数。但注意这只是一种理解方式,实际上lambda表达式产生的类不含有默认构造函数、赋值运算符以及默认析构函数。
  10. 标准库定义了一系列函数对象,在functional头文件中,通过模板的方式实现。(类似于python中的operator模块,里面也有一大堆add/mul之类的可调用对象。)比如我们希望按照字典序排序字符串,可以在sort的第三个参数中传入greater<string>。甚至这里面的函数对象可以对指针操作,比如less<string*>可以比较指针的内存地址,而如果是我们手动比较两个无关指针,将会产生未定义的行为。
本站总访问量