这里的non-member函数对应的另一个函数是member函数,member函数暗含着一个this参数,所谓的“若所有参数比需要类型转换,必须采用non-member函数”的原因就在于,member函数暗含的*this参数是转换不了的!例如我们前面提到的operator应用于Rational,假如operator*是Rational的一个member函数:
class Rational{
public:
Rational( int n = 0, int d = 1 ):num(n), den(d){
}
int numerator() const;
int denumerator() const;
const Rational operator* ( const Rational& lhs, const Rational& rhs ) const;//书上代码觉得有错误,因为member function operator*有两个参数时,表示三元操作符。而书上*应该是表示乘号,只要一个参数就可以了
private:
int num;
int den;
};
Rational oneEighth( 1, 8 );
Rational oneHalf( 1, 2 );
Rational result = oneHalf * oneEighth; //调用oneHalf.operator*( oneEighth );
Rational result2 = oneEighth * oneHalf; //调用oneEighth.operator*( oneHalf );
result = oneHalf * 2; //调用oneHalf.operator*( 2 ); 2隐式转换。
result2 = 2 * oneHalf; //错误,没有函数可调用
从Rational类设计者的角度来看,拿一个Rational对象跟一个整数相乘应该是被允许的,这比较符合我们对它的期望,前面我们也提到,尽量让类的设计与内置类型的行为相一致。若函数设计成non-member函数,将不再受this参数限制,所以参数都可能被隐式转换,当执行时,编译器会首先在该类中查找有没有重载,然后再到命名空间和global区域查找(也就是查找non-member operator):
const Rational operator* ( const Rational& lhs, const Rational& rhs );
result = 2 * oneHalf; //2首先被隐式转换为Rational,成功。
至于该operator*是否应该被设为Rational的friend函数,在这里显然是不需要的。别忘了,让越少的代码接触到数据,封装性越高,我们对private部分能做的改动的弹性便越高。