1. 程式人生 > >C++ Primer 學習筆記 — 隱式類型別轉換

C++ Primer 學習筆記 — 隱式類型別轉換

1.瞭解

explicit用來防止由建構函式定義的隱式轉換。要明白它的作用,首先要了解隱式轉換:可以用單個實參來呼叫的建構函式定義了從形參型別到該類型別的一個隱式轉換。

#include <string>
#include <iostream>

using namespace std;

class Fruit               //定義一個類,名字叫Fruit
{
   public:
	
        Fruit(){}
		
		Fruit(const string &nst, const string &cst = "green"):name(nst),colour(cst){}  //建構函式
 
		bool isSame(const Fruit &otherFruit)   //期待的形參是另一個Fruit類物件,測試是否同名
		{
			return name == otherFruit.name;
		}
		
		void print()              //定義一個輸出名字的成員print()
		{
			cout<<colour<<" "<<name<<endl;
		}
    
	private:
		string name;     //定義一個name成員           
		string colour;   //定義一個colour成員

};

int main()
{
	Fruit apple("apple","green");
 	Fruit orange("orange","yellow");
	cout<<"apple = orange ?: "<<apple.isSame(orange)<<endl;  //沒有問題,肯定不同
	cout<<"apple = \"apple\" ?:"<<apple.isSame(string("apple"))<<endl; //用一個string做形參? 
 
    return 0;
}

 用一個string型別作一個期待Fruit物件形參的函式的引數,結果竟然得出了是true(1),這就是隱式類型別轉換:“可以用單個實參來呼叫的建構函式定義了從形參型別到該型別的一個隱式轉換。”C++ Primer中提到:首先要單個實參,倘若你把建構函式colour的預設實參去掉,也就是定義一個物件必須要兩個引數的時候,此時,編譯將不能通過,然後滿足這個條件後,系統就知道怎麼轉換了,不過這裡比較嚴格:)以前我們構造物件的時候Fruit apple("apple")其實也已經有了一個轉換,從const char *的C風格字串轉換為string,在這裡,你再用apple.isSame("apple")的話,系統不懂得幫你轉換兩次,所以你必須要用string()建構函式來先強制轉換,然後系統才知道幫你從string隱式轉換為Fruit。當然其實你自己也可以幫他完成,如cout<<"apple = \"apple\" ?:"<<apple.isSame(Fruit("apple"))<<endl;
   參考下例 :Fruit apple = Fruit("apple","green");  //定義一個Fruit類物件apple。
   也就是這樣轉換的。不過這就叫顯式轉換了,我們不標出來,系統幫我們完成的,叫隱式的。這裡要說的是,假如你顯示轉換就可以不管有多少引數了,比如在前面提到的必須需要兩個引數的建構函式時的例子。

#include <string>
#include <iostream>

using namespace std;

class Fruit               //定義一個類,名字叫Fruit
{
   public:
	
        Fruit(){}
		
		Fruit(const string &nst, const string &cst):name(nst),colour(cst){}  //建構函式
 
		bool isSame(const Fruit &otherFruit)   //期待的形參是另一個Fruit類物件,測試是否同名
		{
			return name == otherFruit.name;
		}
		
		void print()              //定義一個輸出名字的成員print()
		{
			cout<<colour<<" "<<name<<endl;
		}
    
	private:
		string name;     //定義一個name成員           
		string colour;   //定義一個colour成員

};

int main()
{
	Fruit apple("apple","green");
 	Fruit orange("orange","yellow");
	cout<<"apple = orange ?: "<<apple.isSame(orange)<<endl;  //沒有問題,肯定不同
	cout<<"apple = \"apple\" ?:"<<apple.isSame(Fruit("apple","green"))<<endl; //顯示轉換 
 
    return 0;
}

2.C++ Primer總結

class Sales_item
{
public: 
    Sales_item(const std::string & book);
    Sales_item(std::istream & is);
};

bool same_isbn(Sales_item book)
{
}

std::string null_book = "9-999-99999-9";
item.same_isbn(null_book);
item.same_isbn(cin);

        使用一個string型別物件作為實參傳給same_isbn函式,編譯器使用接收一個string的Sales_item建構函式從null_book生成一個新的Sales_item物件,新生成的(臨時的)Sales_item被傳遞給same_isbn函式。
        將cin隱式轉換為Sales_item。這個轉換執行接收一個istream的Sales_item建構函式。該建構函式通過讀標準輸入來建立一個(臨時的)Sales_item物件。然後該物件被傳遞給same_isbn函式。
         通過將建構函式宣告為explicit,可以防止在需要隱式轉換的上下文中使用建構函式:

class Sales_item
{
public: 
    explicit Sales_item(const std::string & book);
    explicit Sales_item(std::istream & is);
};
explicit關鍵字只能用於類內部的建構函式宣告上。在類的定義體外部所做的定義上不再重複它。
// error: explicit只能用於類內部宣告上
explicit Sales_item::Sales_item(std::istream & is)
{
    is >> *this;
}
現在,兩個建構函式都不能用於隱式地建立物件,前兩個使用都不能編譯
item.same_isbn(null_book); // error
item.same_isbn(cin); // error

3.總結

       C++ Primer中提到:通常,除非有明顯的理由想要定義隱式轉換,否則,但形參建構函式應該為explicit。將建構函式設定為explicit可以避免錯誤,而且當轉換有用時,使用者可以顯式地構造物件。
       

       google的c++規範中提到:explicit的優點是可以避免不合時宜的型別變換,缺點無。所以google約定所有單引數的建構函式都必須是顯示的,只有極少數情況下拷貝建構函式可以不宣告稱explicit。例如作為其他類的透明包裝器的類。

        effective c++中提到:被宣告為explicit的建構函式通常比其non-explicit兄弟更受歡迎。因為它們禁止編譯器執行非預期(往往也不被期望)的型別 轉換。除非我有一個好理由允許建構函式被用於隱式型別轉換,否則我會把它宣告為explicit。我鼓勵你遵循相同的政策。

4.參考文獻

相關推薦

C++ Primer 學習筆記型別轉換

1.瞭解 explicit用來防止由建構函式定義的隱式轉換。要明白它的作用,首先要了解隱式轉換:可以用單個實參來呼叫的建構函式定義了從形參型別到該類型別的一個隱式轉換。 #include <string> #include <iostream>

C++關鍵字explicit與型別轉換

最近在翻閱EffectiveC++一書,就邊學邊做筆記了,之前很多東西沒能及時整理上來,當時的想法是害怕自己在閱讀過程中很多東西不能夠理解的很深刻,之後就是不斷的遺忘再遺忘或者隨著時間的推移就不想去碼字了,時間真是個可怕的東西,年齡大了就開始害怕了。C++術語(Termino

C++ 型別轉換

《C++ Primer》中提到: “可以用 單個形參來呼叫 的建構函式定義了從 形參型別 到 該類型別 的一個隱式轉換。” 這裡應該注意的是, “可以用單個形參進行呼叫” 並不是指建構函式只能有一個形參,而是它可以有多個形參,但那些形參都是有預設實參的。 那麼,什麼是“隱式轉換

淺談C++(4)--型別轉換

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

C++轉換函式和型別轉換

基礎型別轉換基礎型別轉為類型別類型別轉換為基礎型別 1、基礎型別轉換 基礎型別之間的型別轉換,滿足從低精度向高精度的自動轉換,規則如下: (char -> short)-> int -&

[C++]型別轉換(轉)

C++ primer 中有這麼一句話:可以用單個實參來呼叫的建構函式定義了從形參型別到該型別的一個隱式轉換。 這麼解釋: 比如有個類A的物件a的成員函式的引數應該是類A的物件,但是把一個別的型別B的物件b傳進去了,而且這個物件b的型別恰好是A的單引數建構函式

型別轉換

以前我們構造物件的時候Fruit apple("apple")其實也已經有了一個轉換,從const char *的C字串格式,轉為string,在這裡,你再apple.isSame("apple")的話,蠢系統不懂得幫你轉換兩次,所以你必須要用 string()來先強制轉換,然後系統才知道幫你從string隱

C++ Primer 學習筆記_5_變量和基本型(續2)

key 情況 boa 類和對象 類定義 優點 splay 查看 變量定義  變量和基本類型 七、枚舉 枚舉不但定義了整數常量集,並且還把它們聚集成組。 枚舉與簡單的const常量相比孰優孰劣, 通過以下一段代

c++ primer 學習筆記23 友元 static成員

友元機制允許一個類將對其非公有成員的訪問權授予指定的函式或類。友元的宣告以關鍵字 friend 開始。它只能出現在類定義的內部。友元宣告可以出現在類中的任何地方:友元不是授予友元關係的那個類的成員,所以它們不受宣告出現部分的訪問控制影響。 通常,將友元宣告

C++ Primer學習筆記』Chapter 3 string物件、vector物件以及陣列的配套型別C風格字串問題和處理區別

string物件、vector物件以及陣列(指標)配套的型別 無論是string物件還是vector物件,它們都有一個size()的成員函式,因此就可能會有這樣的一個疑問:成員函式size()返回的到底是什麼型別?之所以可能會有而不是一定會有是因為,當我們使用

C++ Primer學習筆記- 第三章:標準庫型別之四

四、標準庫bitset型別 標準庫中bitset型別用來處理二進位制位的有序集,bitset型別簡化了位集的處理,使用bitset時需要包含標頭檔案#include<bitset>     bitset物件的定義和初始化 bitset也是類模板,不過bits

C++ primer學習筆記——第二章 變數和基本型別

一、基本內建型別 C++基本內建型別包括算術型別和空型別。 1.算術型別 算術型別分為兩類:整形(包括字元和布林型在內)和浮點型 bool(布林型)                         長度(位元組):1          取值範圍:false,true

[C/C++] C++ Primer學習筆記

轉義 寫到 十六進制 程序 結果 否則 筆記 end 情況 下面記錄我每天看書學到的以前不太清楚的概念和用法: Day 1 endl:具有輸出換行的效果,並刷新與設備相關聯的緩沖區。 註:在調試程序過程中插入的輸出語句都應刷新輸出流,否則可能會造成程序崩潰,將會導致程序出錯

C++ Primer 學習筆記與思考_7 void和void*指針的使用方法

能夠 amp space turn begin member use mem urn (一)void的含義 void的字面意思是“無類型”,void差點兒僅僅有“凝視”和限制程序的作用,由於從來沒有人會定義一個void變量,讓我們試著來定義: void a;

C轉換

賦值運算符 有一個 ffffff 表達 計時 可能 不同類 類型 有時 這篇文章僅僅針對C語言存在的隱式類型轉換做一些分析,關於C++的這方面研究,有時間我再另外寫一篇文章。 關於隱式類型轉換,是指發生在沒有明確說明的情況下(C語言風格的強制類型轉換就是屬於我們程序員有明

c++ primer 學習筆記——函式的定義與宣告

c++語句 宣告語句:int stone;指出變數的型別為int型,同時用變數stone標識儲存在該記憶體單元中的值。 賦值語句:將值賦給儲存單元。stone=5;或者pounds=stonetolb(stone); 初始化:在宣告變數的同時給變數賦值。int pou

c++primer學習筆記 string的一些額外操作

1.string除了與其他順序容器相同的建構函式,還額外支援另外三個建構函式。 構造string的方法 string s(cp, n) s是cp指向的陣列中前n個字元的拷貝。此陣列至少應該包

C++ primer讀書筆記 7.4 的作用域

一個類就是一個作用域,在類的外部,成員的名字被隱藏起來了 在類的外部定義成員函式時, 要加上類名和作用域運算子 而一旦遇到了類名,定義的剩餘部分在就在類的作用域之內了。包含引數列表和函式體 另一方面,函式的返回型別通常出現在函式名之前,因此如果返回類型別,需要明確指出哪個類定義了該

C++primer 學習筆記——第六章 函式

一、函式基礎 函式:返回型別+函式名字+形參列表+函式體 通過呼叫運算子來執行函式。呼叫運算子的形式是一對圓括號,它作用於一個表示式,該表示式是函式或者指向函式的指標。 形參與實參 實參是形參的初始值。 實參的型別和數量必須與對應的形參型別和數量匹配。即使某個形參不

C++Primer學習筆記+練習答案-第一章

練習答案 Exercise 1.1: Review the documentation for your compiler and determine what file naming convention it uses. Compile and run th