假设有一个有理数类Rational,有一个计算有理数乘法的成员函数operator*,示例如下:
1 #include <iostream> 2 3 class Rational 4 { 5 public: 6 Rational(int numerator = 0, int denominator = 1) 7 { 8 n = numerator; // 分子 9 d = denominator; // 分母 10 } 11 int numerator() const 12 { 13 return n; 14 } 15 int denominator() const 16 { 17 return d; 18 } 19 const Rational operator*(const Rational& rhs) const 20 { 21 return Rational(this->n * rhs.n, this->d * rhs.d); 22 } 23 24 private: 25 int n; 26 int d; 27 }; 28 29 int main() 30 { 31 Rational oneEight(1, 8); 32 Rational oneHalf(1, 2); 33 Rational result1 = oneEight * oneHalf; // 同类型运算 34 Rational result2 = oneHalf * 3; // 混合运算1 35 Rational result3 = 3 * oneHalf; // 混合运算2 36 37 std::cout << result1.numerator() << "/" << result1.denominator() << std::endl; 38 std::cout << result2.numerator() << "/" << result2.denominator() << std::endl; 39 std::cout << result3.numerator() << "/" << result3.denominator() << std::endl; 40 41 return 0; 42 }
如上可见,该乘法运算对于执行同类型运算没有任何问题,为什么对于执行混合运算却有时可以,有时又不可以呢?其实,我们知道执行oneHalf * 3时,编译器调用oneHalf的成员函数,然后对于3执行隐式类型转换(调用Rational的构造函数完成的),转换为Rational后执行乘法运算,因此没出现错误;但是对于3 * oneHalf而言就不同了,因为3并没有相应的成员函数,因此,编译器将试图寻找non-member operator*:result = operator*(2, oneHalf),但是很遗憾,你没有提供这样的函数,因此发出错误。因此结论是:像这种需要发生类型转换才能继续工作的函数,你必须提供一个non-member函数来完成工作,示例如下:
1 const Rational operator*(const Rational& lhs, const Rational& rhs) 2 { 3 return Rational(lhs.numerator() * rhs.numerator(), lhs.denominator() * rhs.denominator()); 4 }
这样的话上述的两种混合调用方式都可以通过了。因此请记住如下结论:
当你设计的某个函数的所有参数(包含this指针所指的那个隐含参数)都可能需要发生类型转换时,那么这个函数必须是non-member函数。