一、考虑下面问题
设计一个class表示有理数,它应该支持隐式类型转换,虽然我们说支持隐式类型转换通常是个不好的主意。这是为了我们设计的类可以和内置类型进行运算。例如和整型:
class Rational {
pbulic:
Rational(int numerator = 0, int denominator = 1); //注意这个构造函数不为explicit
int numerator() const;
int denominator() const; //两个接口 提供对成员的访问
priavte:
....
};
当我们想这个class可以支持运算如加法等。operator*()函数声明为member函数,还是声明为non-member函数?
(1)声明为 member函数
class Rational {
public:
.....
const Rational operator* (const Rational& rhs) const;
};
这个设计能使类的对象很好的运算,例如:
Rational oneEighth(1,8);
Rational oneHalf(1,2);
Rational result = oneHalf * oneEighth;
但是,当对象很一个内置型进行运算时,便会出现问题:
result = oneHalf * 2; //很好
result = 2 * oneHalf; //错误
为什么会这样,考虑上面的等价函数调用形式:
result = oneHalf.operator*(2); //成功
result = 2.operator*(ontHalf); //错误
为什么第一个可以成功呢?2也不是一个Rational类型的对象。因为编译器为这个2进行了隐式类型转换。 为什么第二个没有发生隐式类型转换了?这是因为第一个调用2是作为参数,而第二个不是。
可是作为member函数只能接收一个参数,而我们这里需要两个参数都需要能发生隐式类型转换。所以唯一的办法就是使用non-member函数。
(2) non-member函数实现
class Rational { ... };
const Rational operator* (const Rational& lhs, const Rational& rhs) //一个non-member函数,并没有声明为友元
{
return Rational(lhs.numerator() * rhs.numerator(),
lhs.denominator()* rhs.denominator());
}
......
result = oneHalf * 2; //很好
result = 2 * oneHalf; //通过编译
该把这个函数声明为friend函数?请记住无论何时如果你可以避免friend函数就该避免,破坏封装性。
(3)总结:
如果你需要为某个函数的所有参数(包括被this指针所指的那个隐喻参数)进行类型转换,那么这个函数必须是个non-member.
参考:Effective C++ 3rd(侯捷译)