Item 5: 對定制的“類型轉換函數”保持警覺 C++從C語言那繼承了其隱式轉換,可以實現不同類型之間的轉換,且C++的隱式轉換還存在更令人害怕的轉型,有可能出現數據丟失。對於這些,你無能為力,因為這都是語言自身提供的。然而當你的自定義類型登場時,你可以通過提供某些函數,來作為編譯器的轉型之用。但是為什麼最好不要提供任何類型轉換函數呢? 原因在於:在你為打算也為預期的情況下,此類函數可能會被調用,而其結果可能不正確、不直觀,很難調試。 在C++中,編譯器會通過兩種方式來實現類型的隱式轉換: 1、使用隱式類型轉換符,即關鍵詞operator之後加上一個類型名稱,如operator double(),注意:你不能為此函數指定返回值類型; 2、通過單變量的constructor,包括只有一個參數的constructor,也包括多個參數,但除了第一個參數外其他的參數都是有缺省值的constructor,如Constructor_Name(Type name)和Constructor_Name(Type1 name1,Type2 name2=Default_Value)。 下面我們來分別介紹這兩種方式別調用的調節以及應對措施: 第一種:使用operator重載函數 當為自定義類提供operator double()重載函數時,該重載函數會在以下情況被調用:ClassType temp(1,2); double d=0.5*temp; 大概轉換過程是:對象temp調用operator double()轉換為double temp=1/2;然後與0.5相乘,最後把結果賦值給變量d。 這種情況比較好解決:我們只要以功能對等的另一個函數取代類型轉換操作符,如將operator double() 轉換為 double asDouble()即可。 這樣,當需要轉型時,需要顯示的調用該member function才能實現。 第二種:通過單變量constructor 通過單自變量constructor完成的隱式轉換較難消除。如下例所示: template <class T> class Array{ public: Array(int size); ... T& operator[] (int index); }; Array<int> a(10); Array<int> b(10); for(int i=0; i<10; i++) if(a == b[i]){do something ...} else {do other things...} 因為代碼中把a[i]寫成了a,編譯器原本應該給出錯誤或者警告提示的,但是C++編譯器很聰明,它會想盡辦法找到一個合適的函數以使程序順利執行,因此它發現只要將b[i]通過constructor就可以轉換為Array<int>類型的對象,於是它就放手去做了。 於是問題就出現了,循環的每次比較都發生在a的內容和一個大小為b[i]的臨時數組做比較,結果可想而知。且這樣做因為每次都要構造和析構一個臨時對象,所以十分沒效率。 那該怎麼解決呢? 1、如果你的編譯器支持explicit關鍵詞,就容易解決,只要將constructor做如下聲明即可; explicit Constructor_Name(Type var);這樣編譯器就不會因隱式轉換而調用它了,不過顯式類型轉換仍是允許的哦。 2、如果你的編譯器不支持explicit關鍵詞,那麼只能走彎路,利用C++的規則中的一條:沒有任何一個轉換程序可以內含一個以上的“用戶定制轉換行為”。 我們可以將Array類的constructor進行變換,產生一個新類ArraySize類,該類只用於表明數組的大小。即 class Array { public: class ArraySize { public: ArraySize(int num):theSize(num); ... }; Array(ArraySize size); } 如此一來,當我們定義Array類的對象時:Array<int> a(10);編譯器會發現可以利用ArraySize類的constructor實現int->ArraySize object的轉換,它毫不猶豫地做了,事實也證明這樣做是對的,Array類的constructor的確需要一個ArraySize類的object。對於這個情況是我們需要的隱式轉換,但是對於其他情況呢? 我們來看另一種情況,同上例,if(a == b[i]),我們將a[i]寫成了a,此時會不會發生隱式轉換呢?答案是否定的。 因為對於上面的情況,如果可以成功執行,需要兩個轉換:1)通過ArraySize類的constructor將int b[i]轉換為ArraySize的對象;2)再通過Array類的constructor將ArraySize類的對象轉換為Array<int>類型的對象。由C++規則可知,這樣的轉換程序是禁止的。