條款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.