欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++中的explicit關(guān)鍵字詳解

 更新時(shí)間:2022年07月26日 16:12:33   作者:涼冰難消一腔熱血  
這篇文章主要介紹了C++中的explicit關(guān)鍵字詳解,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下

前言

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

1. 抑制構(gòu)造函數(shù)定義的隱式轉(zhuǎn)換

在要求隱式轉(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;
};

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

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 只對(duì)一個(gè)實(shí)參的構(gòu)造函數(shù)有效。需要多個(gè)實(shí)參的構(gòu)造函數(shù)不能用于執(zhí)行隱式轉(zhuǎn)換,所以無須將這些構(gòu)造函數(shù)指定為 explicit 的。只能在類內(nèi)聲明構(gòu)造函數(shù)時(shí)使用 explicit 關(guān)鍵字,在類外部定義時(shí)不應(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ù)時(shí),它將只能以直接初始化的形式使用。而且,編譯器將不會(huì)在自動(dòng)轉(zhuǎn)換過程中使用該構(gòu)造函數(shù)。

發(fā)生隱式轉(zhuǎn)換的一種情況時(shí)當(dāng)我們執(zhí)行拷貝的初始化時(shí)(使用 = )。此時(shí),我們只能使用直接初始化而不能使用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ù)用于拷貝形式的初始化過程	

2. 為轉(zhuǎn)換顯式地使用構(gòu)造函數(shù)

盡管編譯器不會(huì)將 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));

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

3. 類型轉(zhuǎn)換運(yùn)算符可能產(chǎn)生意外結(jié)果

《C++ prime》第五版,14.9.1中關(guān)于類型轉(zhuǎn)換的介紹:

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

在C++標(biāo)準(zhǔn)的早期版本中,如果類想定義一個(gè)向bool的類型轉(zhuǎn)換,則它常常遇到一個(gè)問題:因?yàn)閎ool是一種算術(shù)類型,所以類類型的對(duì)象轉(zhuǎn)換成bool后就能被用在任何需要算數(shù)類型的上下文中。這樣的類型轉(zhuǎn)換可能引發(fā)意想不到的結(jié)果,特別是當(dāng)istream含有向bool的類型轉(zhuǎn)換時(shí),下面的代碼仍將通過編譯:

int i = 42;
cin << i; // 如果向bool的類型轉(zhuǎn)換不是顯式的,則該代碼在編譯器看來將是合法的!
// 這個(gè)程序只有在輸入數(shù)字的時(shí)候,i會(huì)默認(rèn)為整數(shù),輸入字符串則會(huì)為0

這段程序視圖將輸出運(yùn)算符用作輸入流。因?yàn)閕stream本身并沒有定義<<,所以本來代碼應(yīng)該產(chǎn)生錯(cuò)誤。然而,該代碼能使用istream的bool類型轉(zhuǎn)換運(yùn)算符將cin轉(zhuǎn)換成bool,而這個(gè)bool值接著會(huì)被提升成int并用作內(nèi)置的左移運(yùn)算符的左側(cè)運(yùn)算對(duì)象。這樣一來,提升后的bool值(1或0)最終會(huì)被左移42個(gè)位置。這一結(jié)果顯示與我們的預(yù)期大相徑庭。

4. 顯示的類型轉(zhuǎn)換運(yùn)算符

為了防止這樣的異常情況發(fā)生,C++11新標(biāo)準(zhǔn)引入了顯式的類型轉(zhuǎn)換運(yùn)算符(explicit conversion operator):

class SmallInt {
public:
	// 編譯器不會(huì)自動(dòng)執(zhí)行這一類型轉(zhuǎn)換
	explicit operator int() const {return val;}
	// 其他成員與之前的版本一致
};

和顯示的構(gòu)造函數(shù)一樣,編譯器(通常)也不會(huì)將一個(gè)顯式的類型轉(zhuǎn)換運(yùn)算符用于隱式類型轉(zhuǎn)換:

SmallInt si = 3; // 正確:SmallInt的構(gòu)造函數(shù)不是顯式的
si + 3;			 // 錯(cuò)誤:此處需要隱式的類型轉(zhuǎn)換,但類的運(yùn)算符是顯式的
static_cast<int>(si) + 3;	// 正確:顯示地請(qǐng)求類型轉(zhuǎn)換。這里的static_cast<int>可以進(jìn)行強(qiáng)制類型轉(zhuǎn)換

當(dāng)類型轉(zhuǎn)換運(yùn)算符是顯式的時(shí),我們也能執(zhí)行類型轉(zhuǎn)換,不過必須通過顯式的強(qiáng)制類型轉(zhuǎn)換才可以。

該規(guī)定存在一個(gè)例外,即如果表達(dá)式被用作條件,則編譯器會(huì)將顯式的類型轉(zhuǎn)換自動(dòng)應(yīng)用于它。換句話說,當(dāng)表達(dá)式出現(xiàn)在下列位置時(shí),顯式的類型轉(zhuǎn)換將被隱式地執(zhí)行:

  • if、while及do語句的條件部分
  • for 語句頭的條件表達(dá)式
  • 邏輯非(?。?、邏輯或(||)、邏輯與(&&)的運(yùn)算對(duì)象
  • 條件運(yùn)算符(? : )的條件表達(dá)式

5. explicit練習(xí)

5.1 當(dāng)不使用explict關(guān)鍵字時(shí)

// explicit關(guān)鍵字的作用就是防止類構(gòu)造函數(shù)的隱式自動(dòng)轉(zhuǎn)換
// 并且explicit關(guān)鍵字只對(duì)有一個(gè)參數(shù)的類構(gòu)造函數(shù)有效,如果類構(gòu)造函數(shù)參數(shù)大于
// 或等于兩個(gè)時(shí),是不會(huì)產(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ù), 錯(cuò)誤為: “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釋放_(tái)pstr內(nèi)存指針的時(shí)候可能會(huì)報(bào)錯(cuò), 完整的代碼必須重載運(yùn)算符"=", 并在其中處理內(nèi)存釋放

    return 0;
}

上面的代碼中, “CxString string2 = 10;” 這句為什么是可以的呢? 在C++中, 如果的構(gòu)造函數(shù)只有一個(gè)參數(shù)時(shí), 那么在編譯的時(shí)候就會(huì)有一個(gè)缺省的轉(zhuǎn)換操作:將該構(gòu)造函數(shù)對(duì)應(yīng)數(shù)據(jù)類型的數(shù)據(jù)轉(zhuǎn)換為該類對(duì)象. 也就是說 “CxString string2 = 10;” 這段代碼, 編譯器自動(dòng)將整型轉(zhuǎn)換為CxString類對(duì)象, 實(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é)。

5.2 使用explict關(guān)鍵字時(shí)

// explicit關(guān)鍵字的作用就是防止類構(gòu)造函數(shù)的隱式自動(dòng)轉(zhuǎn)換
// 并且explicit關(guān)鍵字只對(duì)有一個(gè)參數(shù)的類構(gòu)造函數(shù)有效,如果類構(gòu)造函數(shù)參數(shù)大于
// 或等于兩個(gè)時(shí),是不會(huì)產(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)鍵字只對(duì)有一個(gè)參數(shù)的類構(gòu)造函數(shù)有效。
    // 如果類構(gòu)造函數(shù)參數(shù)大于或等于兩個(gè)時(shí), 是不會(huì)產(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ù), 錯(cuò)誤為: “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釋放_(tái)pstr內(nèi)存指針的時(shí)候可能會(huì)報(bào)錯(cuò), 完整的代碼必須重載運(yùn)算符"=", 并在其中處理內(nèi)存釋放

    return 0;
}

5.3 explicit 標(biāo)識(shí)的構(gòu)造函數(shù)中存在一個(gè)默認(rèn)值

但是, 也有一個(gè)例外, 就是當(dāng)除了第一個(gè)參數(shù)以外的其他參數(shù)都有默認(rèn)值的時(shí)候, explicit關(guān)鍵字依然有效, 此時(shí), 當(dāng)調(diào)用構(gòu)造函數(shù)時(shí)只傳入一個(gè)參數(shù), 等效于只有一個(gè)參數(shù)的類構(gòu)造函數(shù),

例子如下:

class CxString  // 使用關(guān)鍵字explicit聲明  
{  
public:  
    int _age;  
    int _size;  
    
    // 此時(shí)該構(gòu)造函數(shù)等效于只有一個(gè)參數(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)操作符"="的重載

到此這篇關(guān)于C++中的explicit關(guān)鍵字詳解的文章就介紹到這了,更多相關(guān)C++ explicit 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++前綴樹字典樹的學(xué)習(xí)與模擬實(shí)現(xiàn)代碼示例

    C++前綴樹字典樹的學(xué)習(xí)與模擬實(shí)現(xiàn)代碼示例

    這篇文章主要介紹了C++前綴樹字典樹的學(xué)習(xí)與模擬實(shí)現(xiàn)代碼示例,Trie又被稱為前綴樹、字典樹,所以當(dāng)然是一棵樹,上面這棵Trie樹包含的字符串集合是{in,inn,int,tea,ten,to},每個(gè)節(jié)點(diǎn)的編號(hào)是我們?yōu)榱嗣枋龇奖慵由先サ?需要的朋友可以參考下
    2023-07-07
  • C語言實(shí)現(xiàn)單詞助手功能

    C語言實(shí)現(xiàn)單詞助手功能

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)單詞小助手,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-10-10
  • c語言數(shù)據(jù)結(jié)構(gòu)與算法之順序表的定義實(shí)現(xiàn)詳解

    c語言數(shù)據(jù)結(jié)構(gòu)與算法之順序表的定義實(shí)現(xiàn)詳解

    這篇文章主要介紹了c語言數(shù)據(jù)結(jié)構(gòu)與算法之順序表的定義實(shí)現(xiàn)詳解,用順序存儲(chǔ)的方式實(shí)現(xiàn)線性表順序存儲(chǔ),把邏輯上相鄰的元素存儲(chǔ)在物理位置上也相鄰的存儲(chǔ)單元中,元素之間的關(guān)系由存儲(chǔ)單元的鄰接關(guān)系來體現(xiàn),需要的朋友可以參考下
    2023-08-08
  • 利用C++實(shí)現(xiàn)簡易的.ini配置文件解析器

    利用C++實(shí)現(xiàn)簡易的.ini配置文件解析器

    這篇文章主要為大家詳細(xì)介紹了如何基于C++編寫一個(gè)簡易的.ini配置文件解析器,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以了解一下
    2023-03-03
  • C++ Boost TypeTraits庫使用詳解

    C++ Boost TypeTraits庫使用詳解

    Boost是為C++語言標(biāo)準(zhǔn)庫提供擴(kuò)展的一些C++程序庫的總稱。Boost庫是一個(gè)可移植、提供源代碼的C++庫,作為標(biāo)準(zhǔn)庫的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開發(fā)引擎之一,是為C++語言標(biāo)準(zhǔn)庫提供擴(kuò)展的一些C++程序庫的總稱
    2022-11-11
  • C語言實(shí)現(xiàn)掃雷游戲(可展開)

    C語言實(shí)現(xiàn)掃雷游戲(可展開)

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)掃雷游戲,實(shí)現(xiàn)掃雷展開和提醒,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-03-03
  • C語言中的switch語句基本用法

    C語言中的switch語句基本用法

    這篇文章主要介紹了C語言中switch語句的基本用法,switch語句是一個(gè)多分支選擇語句,并且可以支持嵌套,感興趣的同學(xué)可以參考閱讀
    2023-03-03
  • 詳解C++編程中的變量相關(guān)知識(shí)

    詳解C++編程中的變量相關(guān)知識(shí)

    這篇文章主要介紹了詳解C++編程中的變量相關(guān)知識(shí),是C++入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-09-09
  • C語言 詳細(xì)講解接續(xù)符和轉(zhuǎn)義符的使用

    C語言 詳細(xì)講解接續(xù)符和轉(zhuǎn)義符的使用

    接續(xù)符是用來告訴編譯器行為的符號(hào),那編譯器遇到接續(xù)符是什么行為呢,就是去掉接續(xù)符,然后把下一行連接到現(xiàn)在這行上面,轉(zhuǎn)義符是主要用于表示無回顯字符,也用于表示常規(guī)字符,轉(zhuǎn)義符必須放在單引號(hào)或者雙引號(hào)里面
    2022-04-04
  • Qt圖形圖像開發(fā)之Qt曲線圖美化QChart QScatterSeries 空心點(diǎn)陣圖,鼠標(biāo)移動(dòng)到上面顯示數(shù)值,鼠標(biāo)移開數(shù)值消失效果實(shí)例

    Qt圖形圖像開發(fā)之Qt曲線圖美化QChart QScatterSeries 空心點(diǎn)陣圖,鼠標(biāo)移動(dòng)到上面顯示數(shù)值,鼠標(biāo)移開

    這篇文章主要介紹了Qt圖形圖像開發(fā)之Qt曲線圖美化QChart QScatterSeries 空心點(diǎn)陣圖,鼠標(biāo)移動(dòng)到上面顯示數(shù)值,鼠標(biāo)移開數(shù)值消失效果實(shí)例,需要的朋友可以參考下
    2020-03-03

最新評(píng)論