条款24:若所有参数皆需类型转换,请为此采用non-member函数
(Declare non-member functions when type conversions should apply to all parameters.)
内容:
平时在我们的coding过程当中,我们有时候会碰到这样一些情况:我传进去的实参与声明函数的形参并不是同
一类型的,函数调用竟然能够成功!这个听起来很不可思议是不是,那么我这里给你说一个编译器的"秘密",也许你在
听完以后,你或许有可能对你说的那些"不可思议的事情"就不以为然了.
我在这里要说的"秘密"就是:当函数的实参类型与形参的出现不一致时候,编译器会尽它最大的能力去寻找合理
类型转换方案进行隐式转换,使它们之间的类型达到一致,从而完成函数的调用过程,当然如果最后还是没有找到合
适的类型转换策略,编译器就会给出"类型不匹配"的编译错误.不怎么理解?好,下面我来举个例子来说明这个问题.
假设现在有一个内置类型int的代理类IntDelegate,当然它就有很多特性,而这里我们要说的是它的乘法操作,
你自然就写出了如下的代码:
class IntDelegate{
public:
IntDelegate(int value = 0):intValue_(value){}
IntDelegate(const IntDelegate& rhs){
intValue_ = rhs.intValue_;
}
const IntDelegate operator*(const IntDelegate& rhs){
IntDelegate result;
result.intValue_ = intValue_ * rhs.intValue_;
return result;
}
int getValue()const{
return intValue_;
}
...
private:
int intValue_;
...
};
wow,写的不错,下面我们来看看有没有什么问题,怎么去看?晕,"实践是检验真理的唯一标准",写代码测试一下:
//test.cpp
...
IntDelegate a(1),b(2);
IntDelegate c = a*b; //ok.
c = a * 2; //Line1: ok.
c = 2 * a; //Line2: error,喔欧,乘法交换律失败罗!shit!
我们先来看Line1,你这里奇怪了?咦?这里的2压根就不是IntDelegate类型,怎么也能编译的过?请注意
IntDelegate的构造函数是一个非explicit构造函数,这也就意味着编译器可以对它进行隐式转换,这种转换等价
代码如下:
IntDelegate tempt(2);
c = a * tempt;
Line1现在该理解了吧?呵呵,我们接着来看Line2,这里的2为什么不能拥有上面的隐式转换呢?原因很简单:只有
位于参数列表内的参数才是隐式转换的合格参与者.显然这里的a才是那位合格者,呜呜....,不公平,我需要两个都能
够进行转换.喔,问题不大!你想想,既然只有作为参数列表才能进行隐式转换,我们这里就很自然地想到把2也作为参
数列表中的一员,这样不就搞定了嘛,呵呵!我们来修改一下代码,这里我们就需要变换一下操作符*的实现函数的函数
原型:
const IntDelegate operator*(const IntDelegate& lhs,const IntDelegate& rhs){
return IntDelegate(lhs.getValue()*rhs.getValue());
}
在运行一下上面的测试代码,全部通过,结果完全真确,恭喜你!
请记住:
■ 如果你需要为某个函数的所有参数(包括被this指针所指的那个隐喻参数)进行类型转换,那么这个函数必须是个non-member.