首页 > 代码库 > Effective C++:条款24:若所有参数皆需类型转换,请为此采用non-member函数

Effective C++:条款24:若所有参数皆需类型转换,请为此采用non-member函数

(一)

假设一个class用来表现有理数,允许整数隐式转换为”有理数似乎很合理。

class Rational{ 
public: 
    Rational(int numerator = 0, int denominator = 1); //刻意不为explicit;允许int-to-Rational隐式转换 
    int numerator()const; 
    int denominator()const; 
};

在支持算术运算符时考虑该由member函数、还是non-member函数来实现:

(1)成员函数的写法:

class Rational{ 
public:
    const Rational operator*(const Rational& rhs) const; 
};

Rational oneEight(1,8);
Rational onehalf(1,2);
Rational result = oneHalf * oneEight;   //nice
result = result * oneEight;   //ok
但是你希望支持混合运算:
result = oneHalf * 2;   //ok 2发生了隐式类型转换。
result = 2 * oneHalf;   //wrong !!!
编译器将上述语句转换为以下语句:

result = oneHalf.operator*(2);   //ok
result = 2.operator*(oneHalf);   //wrong!

oneHalf是一个含operator*函数的class的一个对象。但是2却没有相应的class,编译器会尝试寻找可被以下这般调用的non-member operator*(也就是在命名空间内 或 global作用域内):

result = operator*(2, oneHalf);//wrong!

本例不存在这样一个接受int和Rational作为参数的non-member operator* 因此查找失败。

只有当参数被列于参数列(parameter list)内,这个参数才是隐式类型转换的合格参与者地位相当于“被调用之成员函数所隶属的那个对象”——即this对象的那个隐喻参数,绝不是隐式转换的合格参与者

(二)解决这种问题的方法:

为了支持混合运算。让operator* 成为一个non-member函数,便允许编译器在每一个实参身上执行隐式类型转换:

const Rational operator*(const Rational& lhs, const Rational& rhs) 
{ 
    return Rational(lhs.numerator() * rhs.numerator(), lhs.denominator() * rhs.denominator()); 
}

result = 2 * oneHalf;//ok!终于编译通过了!
operator*是否要成为Rational的friend函数呢?答案是否定的,因为operator*完全籍由Rational的public接口完成任务;

无论何时如果你可以避免friend函数就该避免。


请记住:

如果你需要为某个函数的所有参数(包括被this指针所指的那个隐喻参数)进行类型转换,那么这个函数必须是个non-member。