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

181 阅读1分钟

如果需要为某个函数的所有参数(包括被this指针所指的那个隐喻参数)进行类型转换,那么这个函数必须是个non-member函数。 用书上的例子, 构造一个有理数的类, 在里面自定义一个构造函数, 并且重载*运算符:

using namespace std;
class Rational {
public:
    Rational(int numerator = 0, int denominator = 1) {
        cout << "Create" << endl;
    }
    const Rational operator* (const Rational& rhs)
    {
        Rational rat;
        cout << "Operator * overloading" << endl;
        return rat;
    }
    int numeator() const;
    int denominator() const;
};

通过重载*运算符, 可以很好地实现两个对象的相乘:

#import <Cocoa/Cocoa.h>
#include "test.hpp"

int main(int argc, const char* argv[]) {
    Rational one(1, 2);
    Rational two(4, 5);
    Rational three = one * two; // success
    three = three * one;        // success
}

但是如果你想支持混合运算, 利于一个Rational对象和一个int数相乘就会出现问题:

three = one * 2; // success

*后面接收的是Rational类型, 而我们传的是int类型的2. 为什么还可以success呢? 是因为发生了隐式类型转换. 编译器知道此时确实是传递了一个int,而函数需要的却是Rational;但编译器同时也知道,只要它调用Rational构造函数并赋予传递来的int,就可以构造出适当的Rational出来。换句话说,此时的调用动作在有点像以下的形式:

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

然而当我们这样写构造函数

explicit Rational(int numerator = 0, int denominator = 1) 
{
    cout << "Create" << endl;
}

执行下行代码就会收到报错:Invalid operands to binary expression ('Rational' and 'int') three = one * 2; // failed

接下来我们试试把int 2 放在*的前面

three = 2 * one; // failed

执行这行代码无论构造函数前面有木有explicit都会有Invalid operands to binary expression ('Rational' and 'int')的报错. 因为整数2并没有对应的class,也就没有operator* 成员函数