Last Updated on 2022年9月30日
重载运算符
规定
- 赋值,取下标,调用,箭头,类型转换,这些运算符只能作为成员函数.
- 用户重载的
&&
与||
不会进行短路求值.
习惯
- 重载主要分为全局重载和类内重载,一般而言,二元运算都应该在全局重载(顺序问题).
- 改变对象状态的运算符一般应当设为成员函数,拥有对称性的运算符一般应在类外重载.
- 从技术层面说,重载运算符的参数可以是指针类型的,但是这一般与我们使用语言的习惯不符,所以形参类型最好只是
T
或T&
,而不要是指针. - 定义有关联的重载运算符时一定要考虑兼容性,例如
a<b
为假,a>b
也为假,那么a==b
就应该返回真. - 重载中应当尽可能的保持语义与内置风格一致.
- 例如,如果重载了
++
运算符,那么应当保证++x
和x+=1
及x=x+1
有同样的效果.
- 例如,如果重载了
- 尽量不要重载全局的
operator new
,仅在类内重载它.- 类内重载的
new
和delete
都是static
的,因此,无法使用this
相关的量 - 这两个重载只需要负责分配/销毁空间,构造和析构仍然是编译器自动插入代码执行的.
- 类内重载的
- 取地址运算符由于有着明显且通用的意义,一般不应该重载.
解引用和箭头
- 一般只有行为类似于指针的类才重载
->
和*
->
最终必须返回一个指针p
,obj->
和p->
语义上等价.- 对于
class T1;
,若它的重载->
返回的不是指针,例如返回一个T3
的T3 operator->()
,此时会隐含的继续调用T3::operator->()
,直到返回一个指针.
- 对于
- 习惯上
*
返回某个对象的引用,应当尽可能保证解引用运算符和指针运算符对应同一个对象,以保证(*p).member
和p->member
总是相互等价的
User-defined-literal
- 我们还可以重载全局
operator "" _myname
自定义字面值常量的后缀,例如1001km
这样的常量是允许的.
类型转换运算符
- 我们可以定义类型转换运算符,从而指定从当前类转换到其他类时的行为.该函数在类内定义,无需返回类型,形式为
operator TName(){return var_of_tname}
- 这种特型十分危险,极易引起二义性的问题,使用时要慎重,一定要避免使用.(例如,习惯上只应定义一个到bool类型的explicit转换)
- 在作为条件时,explicit可以被编译器忽略.
- 替代方案是添加一个
to_tname()
成员函数,我们就可以显式的进行转换了.