还是前面那个有理数乘法的例子:
class Rational { public: Rational(int numerrator = 0, int denominator = 1):n(numerrator),d(denominator){} const Rational operator*(const Rational& rhs) { n = n * rhs.n; d = d * rhs.d; return *this; } double getVal() { double result = (double)n / double(d); return result; } private: int n;//分子 int d;//分母 };
那么假如我们调用:
Rational t1(1,2); Rational t2(1,2); Rational t3; t3 = t1 * 3;
是没有问题的,但是如果调用t3 = 3 * t1;编译就不会通过了。这是我们不想看到的情况,因为我们都知道乘法是满足交换律的。问题出在哪呢?
其实t3 = t1 * 3;这句代码中,编译器知道*操作的操作数是一个Rational,所以会调用构造函数把3初始化为一个Rational类的对象,(前提是你的构造函数不是explict)然后再调用Rational操作。而对于 3 * t1,适当做operator*(3,t1)来处理的,可是并不存在一个这样的函数,所以就会报错了。
这个问题的解决办法其实也很简单,将operator*声明为非成员函数:
Rational operator*(const Rational &lhs,const Rational &rhs) { Rational result(lhs.n*rhs.n,lhs.d*rhs.d); return result; }
再将它设为友元,然后不管3在前还是在后,遇到3时总会把它变成一个Rational类的对象。
总之,如果函数的参数(包括this指针)都有可能发生类型转化时,那么这个函数得放在非成员函数中。