如果你需要为某个函数的所有参数(包括this指针所的那个隐喻参数)进行类型转换,那么这个函数必须是non-member
例子:
class Rational {
public:
Rational(intnumerator=0, int denominator=1); //不是explicit,为了支持混合运算
//支持int-to-Rational隐式转换
constRational operator* (const Rational& rhs) const;
intnumerator () const;
intdenominator() const;
private:
intn,d;
};
Rational oneEight(1,8);
Rational oneHalf(1,2);
Rational result=oneEight*oneHalf; //正确
result=oneHalf*2; //正确,隐式类型转换 => result=oneHalf.operator*(2);
//即 const Rational temp(2);result=oneHalf*temp; 构造一个临时性的Rational对象
result=2*oneHalf; //错误 =>result=2.operator*(oneHalf);
oneHalf是一个内含operator*函数的class对象,所以编译器调用该函数。而整数2并没有相应的class,也就没有operator*可供调用。编译器会尝试寻找可被这样调用的non-menber的operator*(在命名空间中或在global作用域内),如下:
result=operator*(2,oneHalf); //错误
因为本例并不存在一个接受int和Rational作为参数的operator*,因此查找失败。
上述只因为涉及non-explicit构造函数,编译器才会这么做,如果Rational构造函数是explicit的,则都不会通过编译。
result=oneHalf*2; //错误,在explicit下,无法将2转换为Rational
resule=2*oneHalf; //同理
而在non-explicit情况下上述表达式也只有一个通过:
result=oneHalf*2; //在non-explicit下 正确
resule=2*oneHalf; //错误,在non-explicit下
NOTE: 只有当参数在初始化列表(parameterlist)内,这个参数才是隐式类型转换合格参与者,地位相当于“被调用的成员函数所隶属的那个对象”(即this对象)的那个隐喻参数。
正确的做法:
class Rational{
};
//non-member函数
const Rational operator* (const Rational& lhs, constRational& rhs)
{
return Rational(lhs.numerator()*rhs.numerator(), lhs.denominator()*rhs.denominator() );
}
是否需要声明为友元呢?
不需要,因为operator*可以完全由Rational的public接口完成任务。而在条款21中必须声明为友元函数,因为用到了其中的private变量。