C++中的explicit關鍵字詳解_第1頁
C++中的explicit關鍵字詳解_第2頁
C++中的explicit關鍵字詳解_第3頁
C++中的explicit關鍵字詳解_第4頁
C++中的explicit關鍵字詳解_第5頁
已閱讀5頁,還剩5頁未讀 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第C++中的explicit關鍵字詳解目錄前言1.抑制構造函數定義的隱式轉換2.為轉換顯式地使用構造函數3.類型轉換運算符可能產生意外結果4.顯示的類型轉換運算符5.explicit練習5.1當不使用explict關鍵字時5.2使用explict關鍵字時5.3explicit標識的構造函數中存在一個默認值

前言

最近在閱讀android底層源碼的時候,發(fā)現其中好多代碼使用了explicit關鍵字,因此這里對explicit關鍵字進行了分析和介紹。

1.抑制構造函數定義的隱式轉換

在要求隱式轉換的程序上下文中,我們可以通過將構造函數聲明為explicit加以組織:

classSales_data{

public:

Sales_data()=default;

Sales_data(conststd::strings,unsignedn,doublep):bookNo(s),units_sold(n),revenue(p*n){}

explicitSales_data(conststd::strings):bookNo(s){}

explicitSales_data(std::istream

Sales_datacombine(constSales_datarhs){

units_sold+=rhs.units_sold;

revenue+=rhs.revenue;;

return*this;

private:

doubleavg_price()const{returnunits_soldrevenue/units_sold:0;}

stringbookNo;

unsignedunits_sold=0;

doublerevenue=0.0;

};

此時,沒有任何構造函數能用于隱式地創(chuàng)建Sales_data對象:下面的兩種用法都無法通過編譯:

Sales_dataitem;//right,調用默認構造函數

Sales_dataitem2("book");//right,調用explicitSales_data(conststd::strings):bookNo(s){}

bine(null_book);//error:string構造函數式explicit的

bine(cin);//error:istream構造函數式explicit的

關鍵字explicit只對一個實參的構造函數有效。需要多個實參的構造函數不能用于執(zhí)行隱式轉換,所以無須將這些構造函數指定為explicit的。只能在類內聲明構造函數時使用explicit關鍵字,在類外部定義時不應重復:

//error:explicit關鍵字只允許出現在類內的構造函數聲明處

explicitSales_data::Sales_data(istreamis){

read(is,*this);

}

note1:explicit構造函數只能用于直接初始化。note2:當使用explicit關鍵字聲明構造函數時,它將只能以直接初始化的形式使用。而且,編譯器將不會在自動轉換過程中使用該構造函數。

發(fā)生隱式轉換的一種情況時當我們執(zhí)行拷貝的初始化時(使用=)。此時,我們只能使用直接初始化而不能使用explicit構造函數:

Sales_datanull_book("book",1,10.0);//right

Sales_dataitem1(null_book);//right,直接初始化

Sales_dataitem2=null_book;//error,不能將explicit構造函數用于拷貝形式的初始化過程

2.為轉換顯式地使用構造函數

盡管編譯器不會將explicit的構造函數用于隱式轉換過程,但是我們可以使用這樣的構造函數顯式地強制進行轉換:

Sales_datanull_book("book",1,10.0);//right

//right:直接初始化

bine(Sales_data(null_book));

//right:static_cast可以使用explicit的構造函數

bine(static_castSales_data(cin));

在第一個調用中,我們直接使用Sales_data的構造函數,該調用通過接受string構造函數創(chuàng)建了一個臨時的Sales_data對象。在第二個調用中,我們使用static_cast執(zhí)行了顯式的而非隱式的轉換。其中static_cast使用istram的構造函數創(chuàng)建了一個臨時的Sales_data對象。

3.類型轉換運算符可能產生意外結果

《C++prime》第五版,14.9.1中關于類型轉換的介紹:

在實踐中,類很少提供類型轉換運算符。在大多數情況下,如果類型轉換自動發(fā)生,用戶可能會感覺比較意外,而不是感覺受到了幫助。然而這條經驗法則存在一種例外情況:對于類來說,定義向bool的類型轉換還是比較普遍的現象。

在C++標準的早期版本中,如果類想定義一個向bool的類型轉換,則它常常遇到一個問題:因為bool是一種算術類型,所以類類型的對象轉換成bool后就能被用在任何需要算數類型的上下文中。這樣的類型轉換可能引發(fā)意想不到的結果,特別是當istream含有向bool的類型轉換時,下面的代碼仍將通過編譯:

inti=42;

cini;//如果向bool的類型轉換不是顯式的,則該代碼在編譯器看來將是合法的!

//這個程序只有在輸入數字的時候,i會默認為整數,輸入字符串則會為0

這段程序視圖將輸出運算符用作輸入流。因為istream本身并沒有定義,所以本來代碼應該產生錯誤。然而,該代碼能使用istream的bool類型轉換運算符將cin轉換成bool,而這個bool值接著會被提升成int并用作內置的左移運算符的左側運算對象。這樣一來,提升后的bool值(1或0)最終會被左移42個位置。這一結果顯示與我們的預期大相徑庭。

4.顯示的類型轉換運算符

為了防止這樣的異常情況發(fā)生,C++11新標準引入了顯式的類型轉換運算符(explicitconversionoperator):

classSmallInt{

public:

//編譯器不會自動執(zhí)行這一類型轉換

explicitoperatorint()const{returnval;}

//其他成員與之前的版本一致

和顯示的構造函數一樣,編譯器(通常)也不會將一個顯式的類型轉換運算符用于隱式類型轉換:

SmallIntsi=3;//正確:SmallInt的構造函數不是顯式的

si+3;//錯誤:此處需要隱式的類型轉換,但類的運算符是顯式的

static_castint(si)+3;//正確:顯示地請求類型轉換。這里的static_castint可以進行強制類型轉換

當類型轉換運算符是顯式的時,我們也能執(zhí)行類型轉換,不過必須通過顯式的強制類型轉換才可以。

該規(guī)定存在一個例外,即如果表達式被用作條件,則編譯器會將顯式的類型轉換自動應用于它。換句話說,當表達式出現在下列位置時,顯式的類型轉換將被隱式地執(zhí)行:

if、while及do語句的條件部分for語句頭的條件表達式邏輯非(?。⑦壿嫽颍▅|)、邏輯與()的運算對象條件運算符(?:)的條件表達式

5.explicit練習

5.1當不使用explict關鍵字時

//explicit關鍵字的作用就是防止類構造函數的隱式自動轉換

//并且explicit關鍵字只對有一個參數的類構造函數有效,如果類構造函數參數大于

//或等于兩個時,是不會產生隱式轉換的,所有explicit關鍵字也就無效了。

#includeiostream

#includestdio.h

#includestring.h

#includestdlib.h

usingnamespacestd;

classCxString//這里沒有使用explicit關鍵字的類聲明,即默認為隱式聲明

public:

char*_pstr;

int_size;

CxString(intsize){

cout"CxString(intsize),size="sizeendl;

_size=size;//string的預設大小

_pstr=(char*)malloc(size+1);

memset(_pstr,0,size+1);

CxString(constchar*p){

intsize=strlen(p);

_pstr=(char*)malloc(size+1);//分配string的內存

strcpy(_pstr,p);

_size=strlen(_pstr);

cout"CxString(constchar*p),strlen(p)="sizeendl;

~CxString(){

if(_pstr!=nullptr){

delete(_pstr);

_pstr=nullptr;

intmain(){

CxStringstring1(24);//right,為CxString預分配24字節(jié)的大小的內存

CxStringstring2=10;//right,為CxString預分配10字節(jié)的大小的內存

CxStringstring3;//error,因為沒有默認構造函數,錯誤為:“CxString”:沒有合適的默認構造函數可用

CxStringstring4("aaaa");//right

CxStringstring5="bbb";//right,調用的是CxString(constchar*p)

CxStringstring6='c';//right,其實調用的是CxString(intsize),且size等于'c'的ascii碼

string1=2;//right,為CxString預分配2字節(jié)的大小的內存

string2=3;//right,為CxString預分配3字節(jié)的大小的內存

CxStringstring3=string1;//right,至少編譯是沒問題的,但是如果析構函數里用free釋放_pstr內存指針的時候可能會報錯,完整的代碼必須重載運算符"=",并在其中處理內存釋放

return0;

}

上面的代碼中,CxStringstring2=10;這句為什么是可以的呢在C++中,如果的構造函數只有一個參數時,那么在編譯的時候就會有一個缺省的轉換操作:將該構造函數對應數據類型的數據轉換為該類對象.也就是說CxStringstring2=10;這段代碼,編譯器自動將整型轉換為CxString類對象,實際上等同于下面的操作:

CxStringstring2(10);

CxStringtemp(10);

CxStringstring2=temp;

但是,上面的代碼中的_size代表的是字符串內存分配的大小,那么調用的第二句CxStringstring2=10;和第六句CxStringstring6=c就顯得不倫不類,而且容易讓人疑惑.有什么辦法阻止這種用法呢答案就是使用explicit關鍵字.我們把上面的代碼修改一下,如5.2小節(jié)。

5.2使用explict關鍵字時

//explicit關鍵字的作用就是防止類構造函數的隱式自動轉換

//并且explicit關鍵字只對有一個參數的類構造函數有效,如果類構造函數參數大于

//或等于兩個時,是不會產生隱式轉換的,所有explicit關鍵字也就無效了。

#includeiostream

#includestdio.h

#includestring.h

#includestdlib.h

usingnamespacestd;

classCxString//這里沒有使用explicit關鍵字的類聲明,即默認為隱式聲明

public:

char*_pstr;

int_size;

int_age;

explicitCxString(intsize){

cout"CxString(intsize),size="sizeendl;

_size=size;//string的預設大小

_pstr=(char*)malloc(size+1);

memset(_pstr,0,size+1);

CxString(constchar*p){

intsize=strlen(p);

_pstr=(char*)malloc(size+1);//分配string的內存

strcpy(_pstr,p);

_size=strlen(_pstr);

cout"CxString(constchar*p),strlen(p)="sizeendl;

//上面也已經說過了,explicit關鍵字只對有一個參數的類構造函數有效。

//如果類構造函數參數大于或等于兩個時,是不會產生隱式轉換的,所以explicit關鍵字也就無效了.

explicitCxString(intage,intsize){

_age=age;

_size=size;

~CxString(){

if(_pstr!=nullptr){

delete(_pstr);

_pstr=nullptr;

intmain(){

CxStringstring1(24);//right,為CxString預分配24字節(jié)的大小的內存

CxStringstring2=10;//error,因為取消了隱式轉換

CxStringstring3;//error,因為沒有默認構造函數,錯誤為:“CxString”:沒有合適的默認構造函數可用

CxStringstring4("aaaa");//right

CxStringstring5="bbb";//right,調用的是CxString(constchar*p)

CxStringstring6='c';//error,其實調用的是CxString(intsize),且size等于'c'的ascii碼,因為取消了隱式轉換

string1=2;//error,因為取消了隱式轉換

string2=3;//error,因為取消了隱式轉換

CxStringstring3=string1;//right,至少編譯是沒問題的,但是如果析構函數里用free釋放_ps

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論