Effective C++设计声明之 若所有参数皆需类型转换,请为此采用non-member函数

Effective C++设计声明之(若所有参数皆需类型转换,请为此采用non-member函数)

问题聚焦:
  • member函数和 non-member 对于隐式类型转换的支持的区别?

通常来说,另classes支持隐式类型转换是个糟糕的注意,当然这条规则有例外是建立数值类型时。

假设有一个Rational 类

class Rational {
public:
	Rational(int numerator = 0, int denominator = 1);
	int numerator() const;
	int denominator() const;
private:
 
};
使用member函数

想支持算数运算诸如加法、乘法等等,但不确定是否该由member函数、non-member函数,或可能的话由non-member friend函数来实现它们。先研究以下将operator*写成Rational成员函数的写法:

class Rational {
public:
	Rational(int numerator = 0, int denominator = 1);
	int numerator() const;
	int denominator() const;
	const Rational operator*(const Rational& rhs) const;
private:
 
};

这个设计能够将两个有理数以最轻松自在的方式相乘:

Rational oneEighth(1, 8);
Rational oneHalf(1, 2);
Rational result = oneHalf * oneEighth;
result = result * oneEighth;

如果要支持混合式运算,比如拿Rational和int相乘。然而当尝试混合式算术,发现只有一半行得通:

result = oneHalf * 2;//很好
result = 2 * oneHalf;//错误!

为什么行不通呢?当以对应的函数形式重写上述两个式子,问题所在便一目了然了:

result = oneHalf.operator*(2);//很好
result = 2.operator*(oneHalf);//错误!

oneHalf是一个内含operator函数的class对象,所以编译器调用该函数。然而整数2并没有相应的class,也就没有operator成员函数,编译器也会尝试寻找可被以下这般调用的non-member operator*(也就是在命名空间内或在global作用域内):

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

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

再次看看result = oneHalf.operator*(2),注意参数是整数2,但Rational::operator*需要的实参却是个Rational对象。**在这里可以接受参数整数2,是因为发生了隐式类型转换。**如果Rational构造函数是explicit,则以下语句都不能编译通过:

result = oneHalf * 2;//编译错误,在explicit构造函数的情况下,无法将2转换为一个Rational
result = 2 * oneHalf;//一样的错误,一样的问题

为什么即使Rational构造函数不是explicit,仍然只有一个可通过编译,另一个不可以:

结论:只有当参数被列于参数列内,这个参数才是隐式类型转换的合格参与者。

使用non-member函数

如果一定要支持混合式算术运算。可行之道:让operator*成为一个non-member函数,允许编译在每一个实参身上执行隐式类型转换:

class Rational {
 
//不再包括operator*
 
};
 
const Rational operator*(const Rational& lhs, const Rational& rhs)//现在成了一个non-member函数
{
        return Rational(lhr.numerator() * rhs.numerator(), lhs.denominator() * rhs.denominator());
}
 
Rational oneFourth(1, 4);
Rational result;
result = oneFourth * 2;//OK
result = 2 * oneFourth;//OK,通过编译!

其他需要考虑:operator*是否应该成为Rational class的一个friend函数呢?

  • 就这个例子而言答案是否定的,因为operator*可以完全由Rational的public接口完成任务,上面代码已表明此中做法。这导出一个重要的观察:member函数的反面是non-member函数,不是friend函数。无论何时如果可以避免friend函数就该避免,friend带来的麻烦往往多过其价值。当然有时候friend有其正当性,但这个事实依然存在:不能够只因函数不该成为member,就自动让它成为friend。
总结:

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

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值