您好,登錄后才能下訂單哦!
今天小編給大家分享一下C++中的explicit關(guān)鍵字怎么使用的相關(guān)知識點(diǎn),內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
在要求隱式轉(zhuǎn)換的程序上下文中,我們可以通過將構(gòu)造函數(shù)聲明為explicit加以組織:
class Sales_data { public: Sales_data() = default; Sales_data(const std::string &s, unsigned n, double p): bookNo(s), units_sold(n), revenue(p*n) {} explicit Sales_data(const std::string &s): bookNo(s) {} explicit Sales_data(std::istream&); Sales_data& combine(const Sales_data &rhs) { units_sold += rhs.units_sold; revenue += rhs.revenue;; return *this; } private: double avg_price() const {return units_sold ? revenue / units_sold : 0; } string bookNo; unsigned units_sold = 0; double revenue = 0.0; };
此時,沒有任何構(gòu)造函數(shù)能用于隱式地創(chuàng)建Sales_data對象:下面的兩種用法都無法通過編譯:
Sales_data item; // right, 調(diào)用默認(rèn)構(gòu)造函數(shù) Sales_data item2("book"); // right, 調(diào)用explicit Sales_data(const std::string &s): bookNo(s) {} item.combine(null_book); // error: string構(gòu)造函數(shù)式explicit的 item.combine(cin); // error: istream構(gòu)造函數(shù)式explicit的
關(guān)鍵字 explicit 只對一個實(shí)參的構(gòu)造函數(shù)有效。需要多個實(shí)參的構(gòu)造函數(shù)不能用于執(zhí)行隱式轉(zhuǎn)換,所以無須將這些構(gòu)造函數(shù)指定為 explicit 的。只能在類內(nèi)聲明構(gòu)造函數(shù)時使用 explicit 關(guān)鍵字,在類外部定義時不應(yīng)重復(fù):
// error: explicit 關(guān)鍵字只允許出現(xiàn)在類內(nèi)的構(gòu)造函數(shù)聲明處 explicit Sales_data::Sales_data(istream& is) { read(is, *this); }
note1: explicit 構(gòu)造函數(shù)只能用于直接初始化。
note2: 當(dāng)使用explicit 關(guān)鍵字聲明構(gòu)造函數(shù)時,它將只能以直接初始化的形式使用。而且,編譯器將不會在自動轉(zhuǎn)換過程中使用該構(gòu)造函數(shù)。
發(fā)生隱式轉(zhuǎn)換的一種情況時當(dāng)我們執(zhí)行拷貝的初始化時(使用 = )。此時,我們只能使用直接初始化而不能使用explicit構(gòu)造函數(shù):
Sales_data null_book("book", 1, 10.0); // right Sales_data item1(null_book); // right,直接初始化 Sales_data item2 = null_book; // error, 不能將explicit 構(gòu)造函數(shù)用于拷貝形式的初始化過程
盡管編譯器不會將 explicit 的構(gòu)造函數(shù)用于隱式轉(zhuǎn)換過程,但是我們可以使用這樣的構(gòu)造函數(shù)顯式地強(qiáng)制進(jìn)行轉(zhuǎn)換:
Sales_data null_book("book", 1, 10.0); // right // right: 直接初始化 item.combine(Sales_data(null_book)); // right: static_cast可以使用explicit的構(gòu)造函數(shù) item.combine(static_cast<Sales_data>(cin));
在第一個調(diào)用中,我們直接使用Sales_data的構(gòu)造函數(shù),該調(diào)用通過接受string構(gòu)造函數(shù)創(chuàng)建了一個臨時的 Sales_data 對象。在第二個調(diào)用中,我們使用 static_cast 執(zhí)行了顯式的而非隱式的轉(zhuǎn)換。其中 static_cast 使用 istram 的構(gòu)造函數(shù)創(chuàng)建了一個臨時的Sales_data對象。
《C++ prime》第五版,14.9.1中關(guān)于類型轉(zhuǎn)換的介紹:
在實(shí)踐中,類很少提供類型轉(zhuǎn)換運(yùn)算符。在大多數(shù)情況下,如果類型轉(zhuǎn)換自動發(fā)生,用戶可能會感覺比較意外,而不是感覺受到了幫助。然而這條經(jīng)驗(yàn)法則存在一種例外情況:對于類來說,定義向bool的類型轉(zhuǎn)換還是比較普遍的現(xiàn)象。
在C++標(biāo)準(zhǔn)的早期版本中,如果類想定義一個向bool的類型轉(zhuǎn)換,則它常常遇到一個問題:因?yàn)閎ool是一種算術(shù)類型,所以類類型的對象轉(zhuǎn)換成bool后就能被用在任何需要算數(shù)類型的上下文中。這樣的類型轉(zhuǎn)換可能引發(fā)意想不到的結(jié)果,特別是當(dāng)istream含有向bool的類型轉(zhuǎn)換時,下面的代碼仍將通過編譯:
int i = 42; cin << i; // 如果向bool的類型轉(zhuǎn)換不是顯式的,則該代碼在編譯器看來將是合法的! // 這個程序只有在輸入數(shù)字的時候,i會默認(rèn)為整數(shù),輸入字符串則會為0
這段程序視圖將輸出運(yùn)算符用作輸入流。因?yàn)閕stream本身并沒有定義<<,所以本來代碼應(yīng)該產(chǎn)生錯誤。然而,該代碼能使用istream的bool類型轉(zhuǎn)換運(yùn)算符將cin轉(zhuǎn)換成bool,而這個bool值接著會被提升成int并用作內(nèi)置的左移運(yùn)算符的左側(cè)運(yùn)算對象。這樣一來,提升后的bool值(1或0)最終會被左移42個位置。這一結(jié)果顯示與我們的預(yù)期大相徑庭。
為了防止這樣的異常情況發(fā)生,C++11新標(biāo)準(zhǔn)引入了顯式的類型轉(zhuǎn)換運(yùn)算符(explicit conversion operator):
class SmallInt { public: // 編譯器不會自動執(zhí)行這一類型轉(zhuǎn)換 explicit operator int() const {return val;} // 其他成員與之前的版本一致 };
和顯示的構(gòu)造函數(shù)一樣,編譯器(通常)也不會將一個顯式的類型轉(zhuǎn)換運(yùn)算符用于隱式類型轉(zhuǎn)換:
SmallInt si = 3; // 正確:SmallInt的構(gòu)造函數(shù)不是顯式的 si + 3; // 錯誤:此處需要隱式的類型轉(zhuǎn)換,但類的運(yùn)算符是顯式的 static_cast<int>(si) + 3; // 正確:顯示地請求類型轉(zhuǎn)換。這里的static_cast<int>可以進(jìn)行強(qiáng)制類型轉(zhuǎn)換
當(dāng)類型轉(zhuǎn)換運(yùn)算符是顯式的時,我們也能執(zhí)行類型轉(zhuǎn)換,不過必須通過顯式的強(qiáng)制類型轉(zhuǎn)換才可以。
該規(guī)定存在一個例外,即如果表達(dá)式被用作條件,則編譯器會將顯式的類型轉(zhuǎn)換自動應(yīng)用于它。換句話說,當(dāng)表達(dá)式出現(xiàn)在下列位置時,顯式的類型轉(zhuǎn)換將被隱式地執(zhí)行:
if、while及do語句的條件部分
for 語句頭的條件表達(dá)式
邏輯非(?。⑦壿嫽颍▅|)、邏輯與(&&)的運(yùn)算對象
條件運(yùn)算符(? : )的條件表達(dá)式
// explicit關(guān)鍵字的作用就是防止類構(gòu)造函數(shù)的隱式自動轉(zhuǎn)換 // 并且explicit關(guān)鍵字只對有一個參數(shù)的類構(gòu)造函數(shù)有效,如果類構(gòu)造函數(shù)參數(shù)大于 // 或等于兩個時,是不會產(chǎn)生隱式轉(zhuǎn)換的,所有explicit關(guān)鍵字也就無效了。 #include <iostream> #include <stdio.h> #include <string.h> #include <stdlib.h> using namespace std; class CxString // 這里沒有使用explicit關(guān)鍵字的類聲明,即默認(rèn)為隱式聲明 { public: char *_pstr; int _size; CxString(int size) { cout << "CxString(int size), size = " << size << endl; _size = size; // string的預(yù)設(shè)大小 _pstr = (char*)malloc(size + 1); memset(_pstr, 0, size + 1); } CxString(const char *p) { int size = strlen(p); _pstr = (char*)malloc(size + 1); // 分配string的內(nèi)存 strcpy(_pstr, p); _size = strlen(_pstr); cout << "CxString(const char *p), strlen(p) = " << size << endl; } ~CxString() { if (_pstr != nullptr) { delete(_pstr); _pstr = nullptr; } } }; int main() { CxString string1(24); // right, 為CxString預(yù)分配24字節(jié)的大小的內(nèi)存 CxString string2 = 10; // right, 為CxString預(yù)分配10字節(jié)的大小的內(nèi)存 CxString string3; // error, 因?yàn)闆]有默認(rèn)構(gòu)造函數(shù), 錯誤為: “CxString”: 沒有合適的默認(rèn)構(gòu)造函數(shù)可用 CxString string4("aaaa"); // right CxString string5 = "bbb"; // right, 調(diào)用的是CxString(const char *p) CxString string6 = 'c'; // right, 其實(shí)調(diào)用的是CxString(int size), 且size等于'c'的ascii碼 string1 = 2; // right, 為CxString預(yù)分配2字節(jié)的大小的內(nèi)存 string2 = 3; // right, 為CxString預(yù)分配3字節(jié)的大小的內(nèi)存 CxString string3 = string1; // right, 至少編譯是沒問題的, 但是如果析構(gòu)函數(shù)里用free釋放_pstr內(nèi)存指針的時候可能會報錯, 完整的代碼必須重載運(yùn)算符"=", 并在其中處理內(nèi)存釋放 return 0; }
上面的代碼中, “CxString string2 = 10;” 這句為什么是可以的呢? 在C++中, 如果的構(gòu)造函數(shù)只有一個參數(shù)時, 那么在編譯的時候就會有一個缺省的轉(zhuǎn)換操作:將該構(gòu)造函數(shù)對應(yīng)數(shù)據(jù)類型的數(shù)據(jù)轉(zhuǎn)換為該類對象. 也就是說 “CxString string2 = 10;” 這段代碼, 編譯器自動將整型轉(zhuǎn)換為CxString類對象, 實(shí)際上等同于下面的操作:
CxString string2(10); 或 CxString temp(10); CxString string2 = temp;
但是, 上面的代碼中的_size代表的是字符串內(nèi)存分配的大小, 那么調(diào)用的第二句 “CxString string2 = 10;” 和第六句 “CxString string6 = ‘c’;” 就顯得不倫不類, 而且容易讓人疑惑. 有什么辦法阻止這種用法呢? 答案就是使用explicit關(guān)鍵字. 我們把上面的代碼修改一下, 如5.2小節(jié)。
// explicit關(guān)鍵字的作用就是防止類構(gòu)造函數(shù)的隱式自動轉(zhuǎn)換 // 并且explicit關(guān)鍵字只對有一個參數(shù)的類構(gòu)造函數(shù)有效,如果類構(gòu)造函數(shù)參數(shù)大于 // 或等于兩個時,是不會產(chǎn)生隱式轉(zhuǎn)換的,所有explicit關(guān)鍵字也就無效了。 #include <iostream> #include <stdio.h> #include <string.h> #include <stdlib.h> using namespace std; class CxString // 這里沒有使用explicit關(guān)鍵字的類聲明,即默認(rèn)為隱式聲明 { public: char *_pstr; int _size; int _age; explicit CxString(int size) { cout << "CxString(int size), size = " << size << endl; _size = size; // string的預(yù)設(shè)大小 _pstr = (char*)malloc(size + 1); memset(_pstr, 0, size + 1); } CxString(const char *p) { int size = strlen(p); _pstr = (char*)malloc(size + 1); // 分配string的內(nèi)存 strcpy(_pstr, p); _size = strlen(_pstr); cout << "CxString(const char *p), strlen(p) = " << size << endl; } // 上面也已經(jīng)說過了, explicit關(guān)鍵字只對有一個參數(shù)的類構(gòu)造函數(shù)有效。 // 如果類構(gòu)造函數(shù)參數(shù)大于或等于兩個時, 是不會產(chǎn)生隱式轉(zhuǎn)換的, 所以explicit關(guān)鍵字也就無效了. explicit CxString(int age, int size) { _age = age; _size = size; } ~CxString() { if (_pstr != nullptr) { delete(_pstr); _pstr = nullptr; } } }; int main() { CxString string1(24); // right, 為CxString預(yù)分配24字節(jié)的大小的內(nèi)存 CxString string2 = 10; // error, 因?yàn)槿∠穗[式轉(zhuǎn)換 CxString string3; // error, 因?yàn)闆]有默認(rèn)構(gòu)造函數(shù), 錯誤為: “CxString”: 沒有合適的默認(rèn)構(gòu)造函數(shù)可用 CxString string4("aaaa"); // right CxString string5 = "bbb"; // right, 調(diào)用的是CxString(const char *p) CxString string6 = 'c'; // error, 其實(shí)調(diào)用的是CxString(int size), 且size等于'c'的ascii碼, 因?yàn)槿∠穗[式轉(zhuǎn)換 string1 = 2; // error, 因?yàn)槿∠穗[式轉(zhuǎn)換 string2 = 3; // error, 因?yàn)槿∠穗[式轉(zhuǎn)換 CxString string3 = string1; // right, 至少編譯是沒問題的, 但是如果析構(gòu)函數(shù)里用free釋放_pstr內(nèi)存指針的時候可能會報錯, 完整的代碼必須重載運(yùn)算符"=", 并在其中處理內(nèi)存釋放 return 0; }
但是, 也有一個例外, 就是當(dāng)除了第一個參數(shù)以外的其他參數(shù)都有默認(rèn)值的時候, explicit關(guān)鍵字依然有效, 此時, 當(dāng)調(diào)用構(gòu)造函數(shù)時只傳入一個參數(shù), 等效于只有一個參數(shù)的類構(gòu)造函數(shù),
例子如下:
class CxString // 使用關(guān)鍵字explicit聲明 { public: int _age; int _size; // 此時該構(gòu)造函數(shù)等效于只有一個參數(shù)的類構(gòu)造函數(shù),explicit可以生效 explicit CxString(int age, int size = 0) { _age = age; _size = size; // 代碼同上, 省略... } CxString(const char *p) { // 代碼同上, 省略... } }; // 下面是調(diào)用: CxString string1(24); // right CxString string2 = 10; // error, 因?yàn)閑xplicit關(guān)鍵字取消了隱式轉(zhuǎn)換 CxString string3; // error, 因?yàn)闆]有默認(rèn)構(gòu)造函數(shù) string1 = 2; // error, 因?yàn)槿∠穗[式轉(zhuǎn)換 string2 = 3; // error, 因?yàn)槿∠穗[式轉(zhuǎn)換 string3 = string1; // error, 因?yàn)槿∠穗[式轉(zhuǎn)換, 除非類實(shí)現(xiàn)操作符"="的重載
以上就是“C++中的explicit關(guān)鍵字怎么使用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學(xué)習(xí)更多的知識,請關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。