使用全局重载运算符而不使用成员运算符重载的最便利的原因之一是在全局版本中的自动类型转换可以针对任一操作数,而成员版本必须保证做操作数已处于正确的形式(即左操作数必须是当前类的对象)。
1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 5 class Number{ 6 int i; 7 public: 8 Number(int ii = 0) :i(ii){ 9 10 } 11 const Number operator+(const Number& rhs){ 12 return Number(i+rhs.i); 13 } 14 15 friend Number operator-(const Number& lhs,const Number& rhs); 16 friend ostream& operator<<(ostream& out,const Number& rhs); 17 18 }; 19 20 Number operator-(const Number& lhs,const Number& rhs){ 21 return Number(lhs.i-rhs.i); 22 } 23 24 ostream& operator<<( ostream& out,const Number& rhs){ 25 26 out << "i=" << rhs.i << endl; 27 return out; 28 } 29 30 int main(){ 31 Number a(43),b(12); 32 33 34 b=a + 1; 35 36 //99 + a;//Error: 没有与这些操作数匹配的 "+" 运算符 操作数类型为:int + Number 37 //上面的这句话翻译过来就是:没有与操作类型为int+Number匹配的"+"运算符。 38 a - b; 39 a - 1; 40 44 - a; 41 42 }
上面的代码要注意a+1;这句话。因为这句话把int类型的1转换成了Number类型,调用了Number(int ii=0);这个构造函数。如果把这个构造函数注释掉,会报错,报错内容为:无法从int转换成Number类型。
在main()函数里面,可以看到增加一个Number到另一个Number进行的很好,这是因为它重载的运算符非常匹配,当编译器看到一个Number后跟一个+号和一个int时,它也能和成员函数Number::operator+()相匹配并且构造函数把int参数转换成Number类型的对象。但当编译器看到一个int +Number类型的操作时,编译器就不知道如何去做了,这是因为它所拥有的是Number::operator+,需要左操作数为Number对象。
对于friend operator-,情况就不同了,编译器需要填满两个参数,它不是限定Number作为左操作数,因此看到1-a;这样的表达式不会出错。
幸运的是编译器不会把1-1(int-int)类型的操作转换成(Number-Number)操作。编译器会首先匹配最简单的可能性。