0.概述
如果需要为某个函数的所有参数(包括被this 指针所指的那个隐喻参数)进行类型转换,那么这个函数必须是个non-member。
1.例:有理数类
class Rational {
public:
Rational(int numerator = 0, // ctor is deliberately not explicit;
int denominator = 1); // 允许隐式转换int-to-Rational
// conversions
int numerator() const; // accessors for numerator and
int denominator() const; // denominator — see Item22
private:
...
};
1.1 将operator*写为成员函数
class Rational {
public:
...
const Rational operator*(const Rational& rhs) const;
};
使用示例:
Rational oneEighth(1, 8);
Rational oneHalf(1, 2);
Rational result = oneHalf * oneEighth; // fine
result = result * oneEighth; // fine
尝试混合式运算:
result = oneHalf * 2; // 可
result = 2 * oneHalf; // 报错!
上式中的乘法显然不满足交换律,以对应的函数形式重写两个式子:
result = oneHalf.operator*(2); // fine
result = 2.operator*(oneHalf); // error!
oneHalf是一个内含operator*函数的class的对象,所以编译器调用该函数。然而整数2并没有相应的class,也就没有operator*成员函数。编译器也会尝试寻找非成员operator*(也就是在命名空间内或在global作用域内):
result = operator*(2, oneHalf);
但这样的函数在本例中并不存在,查找失败。
那为什么第一个调用式子可以通过?发生了隐式类型转换(通过构造函数)。
const Rational temp(2); // create a temporary Rational object from 2
result = oneHalf * temp; // same as oneHalf.operator*(temp);
如果构造函数是explicit,则两个式子都无法通过编译。
1.2 使operator*成为非成员函数
并允许编译器在每个实参上执行隐式类型转换,就可以支持混合式算术运算
class Rational {
... // contains no operator*
};
const Rational operator*(const Rational& lhs, const Rational& rhs) //非成员函数
{
return Rational(lhs.numerator() * rhs.numerator(),
lhs.denominator() * rhs.denominator());
}
Rational oneFourth(1, 4);
Rational result;
result = oneFourth * 2; // fine
result = 2 * oneFourth; // hooray, it works!
还有一点需要考虑:operator*是否该成为友元函数?
不,成员函数的反面是非成员函数而非友元函数。