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

版权声明:仅供参考与学习交流 https://blog.csdn.net/lym940928/article/details/81989024

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

Declare non-member functions when type conversions should apply to all parameters.
在上一部分钟,我们想要Rational class可以去支持混合式的算数运算,但是却出现了问题:

  • 在Rational构造函数不是explicit的情况下,为何一个可以通过编译,另一个却是不行?
result = oneHalf.operator*(2);  //成功!
result = 2.operator*(oneHalf);  //错误!

原因就是:

  • 只有当参数被列于参数列(parameter list)内,这个参数才是隐式类型转换的合格参与者。

这也就解释了为何第一次可以通过编译,而第二次不可以:因为第一次的调用伴随着一个放在参数列内的参数,第二次则没有。

因此,最终的解决方案就出现了:

  • 让operator* 成为一个non-member函数,并允许编译器在每一个实参身上执行隐式类型转换:
class Rational {            //并不包含operator*的定义
    ...
};

const Rational operator*(const Rational& lhs,   //构成了一个non-member函数
                         const Rational& rhs)
{   
    return Rational(lhs.numerator() * rhs.numerator(),
                    lhs.denominator() * rhs.denominator());
}
Rational oneForth(1, 4);
Rational result;
result = oneForth * 2;      //成功了!
result = 2 * oneForth;      //成功了!!

此时,问题得到了顺利的解决,不过仍然有一点需要考虑:

  • operator* 是否应该是Rational class的一个friend函数呢?

就这个例子而言,答案是否定的!因为operator* 完全可以由Rational的public接口完成任务,上面的代码也是这样去实现的。(public的构造函数和分子分母的访问函数)
于是,这也又引发了一个重要的结论:

  • member函数的反面是non-member函数,而不是friend函数。

有很多程序员会有这样的误解,如果一个“与某class相关”的函数不应该成一个member,那么它就一定要称为friend,这是一个错误的理解。无论何时如果可以避免使用friend函数,就应该去避免。虽然friend有其正当性,但下面的结论依然成立:

  • 不能只因为函数不该成为member,就自动让它成为friend。

最后:

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

猜你喜欢

转载自blog.csdn.net/lym940928/article/details/81989024