C++主題——轉換函數


出處














































































 


C++主題——轉換函數 

轉換函數的基本規則:
        

轉換函數只能是成員函數,無返回值,空參數。
        不能定義到void的轉換,也不允許轉換成數組或者函數類型。
        轉換常定義爲const形式,原因是它並不改變數據成員的值。

轉換函數所引出的問題:
        轉換操作符過於強大,它可以定義到一種內置類型的轉換,然而這種內置類型本身是可能繼續轉換成其他的內置類型的(不能轉換到一個自定義類型後再轉換到另一個自定義類型),如 operator int() const 定義了到int型的轉換,然後int型可以轉換到float、double、long等類型, 這樣極不容易確定編譯器爲我們做了什麼,在出現問題後,也極不容易定位錯誤。
        當類類型定義了一個到基本類型A的轉換後,他可能在實際中轉換到另一基本類型B,這時如果再定義一個到基本類型C的轉換,而C也可以轉換到B。這樣,就會在實際運用中產生二義性,如A爲int,B爲long double,C爲double,在產生自定義類型的對象時,需要轉換,就會使得編譯器並不知道如何處理,到底是調用哪個轉換。
         使用自定義轉換時,有兩個潛在的缺陷:1.定義轉換多,會像上述那樣引發二義性;2.一些轉換利大於弊。避免前者的方法是,最好在定義到內置類型的轉換時,只定義一個(內置類型之間的轉換太靈活了)。避免後者的除了經驗和反覆思考沒什麼好辦法。
         《More Effective C++》建議將轉換函數設計成一種asType()的函數形式,就像std::String中的成員函數c_str一樣,提供一個函數,而不是一個轉換。

轉換函數引出的擴展問題:
        構造函數也會在標準類型到類類型的轉換中起到意想不到的負面影響。當在某處需要一個類對象時,他會隱式調用構造函數完成轉換,而當已經存在一個單參數構造函數接受了一種內置類型完成構造,又定義了一個單參數構造函數接受不同內置類型完成構造時,也會出現和轉換函數相同的問題——二義性。
        構造函數和轉換函數之間也可能存在二義性。如:

class Integer
{
public:
       Integer(
int i = 0);
       
operator int () const;
       friend Integer 
operator + (const Integer& i1, const Integer& i2);  
private:
       
int m_ivalue;
};


Integer A1,A2;
Integer A3 
= A1 + A2;
int i = A3 + 1;//error

        這時,int  i = A3 + 1;該如何做?是把A3轉化成int做+運算?還是把1轉換成Integer做operator+運算?
        如果定義了到算術內置操作符的轉換,就不要在定義接受算術類型的操作符的重載版本。如果用戶需要使用這些操作符,則轉換操作將轉換你所定義的類型對象,然後可以使用內置操作符。
        解決這個衝突的一個比較簡單的方法是把Integer的構造函數聲明成顯示的explicit。
        另一種比較複雜的方法是在Integer內部做一個proxy class代理類,把Integer的構造函數的參數聲明成這個代理類而不是int。然後讓這個代理類做一個構造函數接受一個int的類型。這樣在需要A類型的隱式轉換時,要先用int的值構造一個代理類型,然後再由Integer構造函數構造一個對象完成轉換,這是不被允許的,兩層的用戶自定義類型間的轉換編譯器不支持,所以可以起到避免隱式轉換的作用。
        (關於proxy class,可以看《More Effective C++》的條款30,那裏有精彩的介紹)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章