重载运算符

Last Updated on 2020年4月15日

重载运算符

规定

  • 赋值,取下标,调用,箭头,类型转换,这些运算符只能作为成员函数.
  • 用户重载的&&||不会进行短路求值.

习惯

  • 重载主要分为全局重载和类内重载,一般而言,二元运算都应该在全局重载(顺序问题).
  • 改变对象状态的运算符一般应当设为成员函数,拥有对称性的运算符一般应在类外重载.
  • 一种优秀的风格是,在类内定义所有一元运算符,这些运算符可以直接修改对象.在类外定义所有的二元运算符,二元运算符通过调用一元运算符来实现功能.
  • 从技术层面说,重载运算符的参数可以是指针类型的,但是这一般与我们使用语言的习惯不符,所以形参类型最好只是TT&,而不要是指针.
  • 定义有关联的重载运算符时一定要考虑兼容性,例如a<b为假,a>b也为假,那么a==b就应该返回真.
  • 重载中应当尽可能的保持语义与内置风格一致.
    • 例如,如果重载了++运算符,那么应当保证++xx+=1x=x+1有同样的效果.
  • 尽量不要重载全局的operator new,仅在类内重载它.
    • 类内重载的newdelete都是static的,因此,无法使用this相关的量
    • 这两个重载只需要负责分配/销毁空间,构造和析构仍然是语言底层自动执行的.
  • 取地址运算符由于有着明显且通用的意义,一般不应该重载.

解引用和箭头

  • 一般只有行为类似于指针的类才重载->*
  • ->最终必须返回一个指针p,obj->p->语义上等价.
    • 对于 class T1;,若它的重载->返回的不是指针,例如返回一个T3T3 operator->(),此时会隐含的继续调用T3::operator->(),直到返回一个指针.
  • 习惯上*返回某个对象的引用,应当尽可能保证解引用运算符和指针运算符对应同一个对象,以保证(*p).memberp->member总是相互等价的

User-defined-literal

  • 我们还可以重载全局operator "" _myname自定义字面值常量的后缀,例如1001km这样的常量是允许的.

类型转换运算符

  • 我们可以定义类型转换运算符,从而指定从当前类转换到其他类时的行为.该函数在类内定义,无需返回类型,形式为operator TName(){return var_of_tname}
  • 这种特型十分危险,极易引起二义性的问题,使用时要慎重,一定要避免使用.(例如,习惯上只应定义一个到bool类型的explicit转换)
    • 在作为条件时,explicit可以被编译器忽略.
  • 替代方案是添加一个to_tname()成员函数,我们就可以显式的进行转换了.