重载操作符
原型:返回类型 operator操作符(形参);
注意事项:
(1)不能通过连接其他合法符号来创建任何新的操作符,如下是错误的:
sales_item operator**(const sales_item &org); //error 不能通过连接其他合法操作符来创建任何新的操作符
(2)重载操作符必须一个具有类类型,类成员的话因为有一个默认的本类this,所以也满足
sales_item operator+(const int a, const int b); //error 必须至少提供一个类类型
sales_item operator+( const int b ); // ok 默认this为类类型
注意:用于内置类型的操作符含义不能变,也不能为任何内置类型定义额外的新的操作符(如数组),如下
int operator+(int, int); //error 因为内置已经定义+操作符
(3)优先级和结合性是固定的,如下
x==y+z
y、z先使用重载操作符+,然后将计算的结果与x 作为形参调用重载操作符==
(4)重载操作符默认使用实参是非法的,除了函数调用操作符operator()
//sales_item operator+(const int b = 0); //error 不能有默认实参
(5)不再具备短路求值
默认的AND,OR,","有求值顺序,但是重载的版本不能保证,所以重载这些操作符不是一种好的做法。
(6)类成员与非成员
作为成员有一个隐含的this形参,限定为第一个形参,this指向左操作数。一般将算术和关系操作符定义为非成员函数,将赋值操作符定义为成员函数。
sales_item& operator+( const sales_item& rhs); //最好声明为非类成员函数
这里为类成员,+操作符的第一个形参就是this,第二个形参就是rhs
(7)操作符重载和友元关系
当定义为非成员函数时,必须设为类的友元函数,以便能够访问类中的成员变量和函数。如下
class sales_item
{
public:
friend istream& operator>>(istream&, sales_item&);
friend ostream& operator<<(ostream&, const sales_item&);
friend sales_item operator+(const sales_item& sale1, const sales_item &sale2);
...
};
//非成员函数重载运算符
istream& operator>>(istream&, sales_item&); //输入
ostream& operator<<(ostream&, const sales_item&); //输出
sales_item operator+(const sales_item&, const sales_item&); //返回值不是引用,不能成为左值,也不能进行连加,如a+b+c
重载操作符的设计
(1)不要重载具有内置含义的操作符
赋值操作符,取地址操作符和逗号操作符对类类型都有默认函数,如果没有特定版本,编译器会自动合成这些版本。所以重载逗号,取地址,逻辑与,逻辑或这些操作符不是好做法,但是赋值操作符有时候需要自己定义。
(2)该定义哪些操作符
为类设计操作符,最好的方式是首先设计类的公用接口,定义了接口之后,就可以考虑将哪些操作符定义为重载操作符。那些逻辑上可以映射到某个操作符的操作可以考虑作为候选的重载操作符。
如相等测试可以使用==,测试对象是否为空可以使用逻辑非操作符!
(3)复合赋值操作符
如果一个类有算术操作符或位操作符,提供相应的复合赋值操作符一般是个好做法。
(4)相等和关系操作符
将要作关联容器键类型的类应定义<操作符。例如sort算法使用<操作符,而find算法使用==操作符;如果定义了==,同样也要定义!=,;如果定义了<,同样也要定义其他关系操作符>,>=,<,<=
(5)该定义为成员还是非成员
- 赋值(=)、下标([])、调用(())、成员访问箭头(->)必须定义为成员,否则编译出错
- 复合赋值操作符应定义为类的成员,不一定非要这么做
- 改变对象状态或给定类型紧密的一些操作,如自增、自减、解引用,通常应定义为类成员。
- 对称的操作符,如算术操作符、相等操作符、关系操作符、位操作符,最好定义为普通的非成员函数。