Effective-cpp-#24

Declare non-member functions when type conversions should apply to all parameters

动机

通常来说,让一个类支持隐式是一个糟糕的设计,它会使得程序变得复杂。但在某些时候,我们需要隐式的转换,考虑一个有理数的类:

1
2
3
4
5
class Rational{
public:
Rational(int numerator=0, int denominator=1);
...
};


如果希望支持算术运算符诸如加法,乘法,那么可以这样实现:

1
2
3
4
5
class Rational{
public:
...
const Rational operator* (const Rational& rhs) const;
};

但这种设计有个问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
Rational oneEighth(1, 8);
Rational oneHalf(1, 2);
Rational result = oneHalf * oneEighth; //可以通过

result = oneHalf * 2; //也可以通过,等同于
result = oneHalf.operator*(2);
//通过的原因,编译器构造了临时对象
const Rational temp(2);
result = oneHalf*temp;

//而如果是想要满足乘法交换律,则会失败:
result = 2 * oneHalf;
//因为2没有相应的class,也就没有operator*函数。当然编译器会尝试在命名空间内或者在global作用域内调用non-member operator*,而这也找不到

解决方法

当然,可以声明explicit 构造函数,这也就保证了一致性,但就无法满足了乘法运算。

为了解决这个问题,也满足了四则运算,我们可以构造一个non-member函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Rational{
...
};

//构造一个non-member函数
const Rational operator*(const Rational& lhs,
const Rational& rhs)
{
return Rational(lhs.numerator()*rhs.numerator(),
lhs.denominator()*lhs.denominator());
}

//这样,就都可以通过了
Rational result;
result = oneFourth * 2;
result = 2 * oneFourth;

这样,就基本解决问题了。。。。

建议

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