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

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

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

Declare non-member functions when type conversions should apply to all parameters.
本章分为两部分。
首先,有以下这条规则:

  • 令class支持隐式类型转换通常是一个糟糕的选择。

但是,这条规则也有例外,最常见的就是建立数值类型时
假设对于一个class用来表示有理数,因此允许整数“隐式转换”为有理数看起来其实是挺合理的:

class Rational {
public:
    Rational(int numerator = 0,     //构造函数刻意不是explicit
             int denominator = 1);  //允许int-to-rational进行隐式转换
    int numerator() const;          //分子的访问函数
    int denominator() const;        //分母的访问函数
private:
    ...
};

接着,对于算数运算的实现,到底应该使用member函数、non-member函数,还是non-member friend函数来实现?
首先,对于operator* 的实现,虽然在条款23中指出,将函数放进相关class内又是会与面向对象守则发生矛盾,但先暂时不考虑,先看一下将operator* 写成Rational 成员函数的写法:

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

这种设计,可以以很方便的方式实现相乘:

Rational oneEight(1, 8);
Rational oneHalf(1, 2);
Rational result = oneHalf * oneEight;   //成功!
result = result * oneEight;             //成功!

暂时看上去,是可行的。但是如果我们此时用两个不同类型的数据进行相乘——比如,一个Rational和int相乘,就可能会出现问题:

result = oneHalf * 2;   //成功!
result = 2 * oneHalf;   //错误!

为什么会出现这样的错误??当我们以对应的函数形式重写上述两行代码:

result = oneHalf.operator*(2);  //成功!
result = 2.operator*(oneHalf);  //错误!

因此,错误就显而易见了:

  • oneHalf是一个内含operator* 函数的class的对象,因此没有问题。
  • 整数2并没有对应的class,也就没有operator* 成员函数。

此时,编译器也会尝试在命名空间内或在global作用域内调用以下形式的non-member operator*

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

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

在这里,上面第一次有参数2,之所以成功,是因为这里发生了所谓的隐式类型转化(implicit type conversion)。
编译器知道此时确实是传递了一个int,而函数需要的却是Rational;但编译器同时也知道,只要它调用Rational构造函数并赋予传递来的int,就可以构造出适当的Rational出来。换句话说,此时的调用动作在有点像以下的形式:

const Rational temp(2);     //根据2建立一个暂时性的Rational对象
result = oneHalf * temp;    //等同于oneHalf.operator*(temp)

这也只是因为涉及到了non-explicit构造函数,编译器才会这样去实现。如果 Rational的构造函数是explicit,下面两条语句都是错误的:

result = oneHalf * 2;   //错误!无法将2转换位Rational
result = 2 * result;    //一样的错误!

此时我们可以看到,这就很难让Rational class支持混合式算数运算了。

猜你喜欢

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