C++隱式類型別轉換

QingLiXueShi發表於2015-01-22

C++可以定義如何將其他型別的物件隱式轉換為我們的類型別或將我們的類型別的物件隱式轉換為其他型別。為了定義到類型別的隱式轉換,需要定義合適的建構函式。

說明:可以用單個實參來呼叫的建構函式定義了從形參型別到該類型別的一個隱式轉換。

 

class Sales_item
{
public:
    Sales_item(const string &book = "") : isbn(book), units_sold(0), revenue(0.0) {}
    Sales_item(istream &is);
};

這兩個建構函式都定義了一個隱式轉換。因此,在期待一個Sales_item型別物件的地方可以使用一個string或一個istream物件。

 

string null_book = "9-999-99999-9";
item.Same_isbn(null_book);

這段程式碼使用一個string型別物件作為實參傳遞給Sales_item的Same_isbn成員函式,該成員函式期待一個Sales_item物件作為實參。編譯器將使用接受一個string的建構函式從null_book生成一個新的Sales_item物件。新生成的(臨時的)Sales_item物件被傳遞給Same_isbn。

 

item.Same_isbn(cin);

這段程式碼將cin物件隱式轉換為Sales_item物件,這個轉換執行接受一個istream的建構函式。這兩個Sales_item是臨時物件,一旦Same_isbn結束,就不能再訪問它。

 

下面看一個例子:http://blog.csdn.net/vagrxie/article/details/1586340

 1 #include <string>
 2 #include <iostream>
 3 using namespace std;
 4 
 5 class Fruit                                //定義一個類,名字叫Fruit
 6 {
 7     string name;                        //定義一個name成員           
 8     string colour;                        //定義一個colour成員
 9 
10 public:
11     bool isSame(const Fruit &otherFruit)   //期待的形參是另一個Fruit類物件,測試是否同名
12     {
13         return name == otherFruit.name;
14     }
15     void print()              //定義一個輸出名字的成員print()
16     {
17         cout<<colour<<" "<<name<<endl;
18     }
19     Fruit(const string &nst,const string &cst = "green"):name(nst),colour(cst){}  //建構函式
20 
21     Fruit(){}
22 };
23 
24 int main(void)
25 {
26     Fruit apple("apple");
27     Fruit orange("orange");
28     cout<<"apple = orange ?: "<<apple.isSame(orange)<<endl;  //沒有問題,肯定不同
29     cout<<"apple = apple ?:"<<apple.isSame(string("apple"))<<endl; //用一個string做形參?
30 
31     return 0;
32 }

我們用string("apple")型別作為一個期待Fruit型別形參的函式的引數,結果是正確的。當把建構函式colour的預設實參去掉,也就是定義一個物件必須要兩個引數的時候,檔案編譯不能通過。Fruit apple("apple")其實也已經有了一個轉換,從const char *的C字串格式,轉為string。但apple.isSame("apple")這樣呼叫肯定是錯的,必須要用string()來先強制轉換,然後系統才知道幫你從string隱式轉換為Fruit。當然你也可以顯式幫它完成,apple.isSame(Fruit("apple"))。

 

可以通過將建構函式宣告為explicit,來防止在需要隱式轉換的上下文中使用建構函式。explicit關鍵字只能用於類內部的建構函式宣告上。在類的定義體外部所做的定義不再重複它。雖然不能隱式轉換了,但顯式轉換還是可以的,例如:apple.isSame(Fruit("apple"))。

說明:

(1)顯式使用建構函式只是終止了隱式地使用建構函式。任何建構函式都可以用來顯式地建立臨時物件。

(2)通常,除非有明顯的理由想要定義隱式轉換,否則,單形參建構函式應該為explicit。將建構函式設定為explicit可以避免錯誤,並且當轉換有用時,使用者可以顯式地構造物件。

(3)將建構函式設定為explicit的好處是可以避免因隱式型別轉換而帶來的語義錯誤,缺點是當使用者的確需要進行相應的型別轉換時,不能依靠隱式型別轉換,必須顯式地建立臨時物件。

相關文章