1、令class支援隱式型別轉換,往往是個糟糕的主意。但有些情況是合理的,比如數值型別。考慮,有理數Rational有分子,分母兩個欄位,預設引數值為0,1。Ration a = 2;我們期望構造一個分子為2,分母為1的有理數,這是非常合理和自然的。因此,Rational的構造方法為Ration(int numerator =0, int denominator =1);不新增explicit。
2、考慮Rational 有個成員方法 operator*,如下:
const Ration operator*(const Rational& rhs) const;
Rational a (1,2);
Rational result;
result = a*2; // OK
result = 2*a; // Error
為什麼?
對於a*2,2會隱式轉化為Rational,而對於2*a,2不會隱式轉化為Rational。這種情況下,編譯器嘗試查詢non-member方法的呼叫,即operator(2,a); 在當前名稱空間或者全域性global作用域查詢不到,報錯。
3、分析下,為什麼對於2*a,2不會隱式轉化為Rational。
呼叫方法的時候,如果沒有完全匹配的方法,編譯器嘗試進行一次隱式型別轉換,使之與方法匹配成功。可認為編譯器做了一次適配的過程,實參與形參型別不一致,把實參轉化為形參的型別,從而匹配成功。
對於a*2,2對應形參,而對於2*a,2對應this指標常量。不能隱式轉化為this指標。再接著思考,為什麼不能轉化為this指標?
假如可以隱式轉化為this指標,那麼有成千上萬的類(沒有宣告explicit構造方法),當呼叫2*a的時候,編譯器必須遍歷每一個類,檢視這個類中是否有* Rational的成員方法,顯然不可能。
4、另外,還有一點,隱式型別轉換隻能進行一次,不能進行多次。也就是說,2 -> XXX -> Person是不可行的。思考下,為什麼?
假如隱式型別轉換允許多次,就意味著,從2 到Person的轉換過程,編譯器必須查詢出所有可能的轉換路徑,這顯然不切實際。即使,找到了所有的轉換路徑,那麼,存在多個轉換路徑,到底使用哪一個呢?
5、怎麼解決上面的問題呢? 即2*a。
既然不能隱式轉換為this指標,那麼就是用non-member方法。這樣的話,無論對於哪個形參需要隱式型別轉化,都可以。編譯器從當前名稱空間或者全域性作用域,查詢operator*(Rational ,Rational),這種形式的方法畢竟很有限。
6、定義的non-member方法,是否需要宣告為Rational的friend方法?
根據經驗,儘量避免使用friend,為啥?因為friend破壞了封裝。因此,如果不需要訪問Rational的private成員,就不要宣告為friend。