C++:explicit關鍵字

来源:https://www.cnblogs.com/crossoverpptx/archive/2023/03/30/17273622.html
-Advertisement-
Play Games

C++中的explicit關鍵字只能用於修飾只有一個參數的類構造函數,它的作用是表明該構造函數是顯示的,而非隱式的,跟它相對應的另一個關鍵字是implicit,意思是隱藏的,類構造函數預設情況下即聲明為implicit(隱式)。 那麼顯示聲明的構造函數和隱式聲明的有什麼區別呢? 來看下麵的例子: c ...


C++中的explicit關鍵字只能用於修飾只有一個參數的類構造函數,它的作用是表明該構造函數是顯示的,而非隱式的,跟它相對應的另一個關鍵字是implicit,意思是隱藏的,類構造函數預設情況下即聲明為implicit(隱式)。

那麼顯示聲明的構造函數和隱式聲明的有什麼區別呢? 來看下麵的例子:

class CxString  // 沒有使用explicit關鍵字的類聲明, 即預設為隱式聲明  
{  
public:  
    char *_pstr;  
    int _size;  
    CxString(int size)  
    {  
        _size = size;                // string的預設大小  
        _pstr = malloc(size + 1);    // 分配string的記憶體  
        memset(_pstr, 0, size + 1);  
    }  
    CxString(const char *p)  
    {  
        int size = strlen(p);  
        _pstr = malloc(size + 1);    // 分配string的記憶體  
        strcpy(_pstr, p);            // 複製字元串  
        _size = strlen(_pstr);  
    }  
    // 析構函數這裡不討論, 省略...  
};  
  
    // 下麵是調用:  
    CxString string1(24);     // 這樣是OK的, 為CxString預分配24位元組的大小的記憶體  
    CxString string2 = 10;    // 這樣是OK的, 為CxString預分配10位元組的大小的記憶體  
    CxString string3;         // 這樣是不行的, 因為沒有預設構造函數, 錯誤為: “CxString”: 沒有合適的預設構造函數可用  
    CxString string4("aaaa"); // 這樣是OK的  
    CxString string5 = "bbb"; // 這樣也是OK的, 調用的是CxString(const char *p)  
    CxString string6 = 'c';   // 這樣也是OK的, 其實調用的是CxString(int size), 且size等於'c'的ascii碼  
    string1 = 2;              // 這樣也是OK的, 為CxString預分配2位元組的大小的記憶體  
    string2 = 3;              // 這樣也是OK的, 為CxString預分配3位元組的大小的記憶體  
    string3 = string1;        // 這樣也是OK的, 至少編譯是沒問題的, free釋放_pstr記憶體指針的時候可能會報錯, 完整的代碼必須重載運算符"=", 併在其中處理記憶體釋放

上面的代碼中, “CxString string2 = 10;” 這句為什麼是可以的呢?

在C++中, 如果的構造函數只有一個參數時, 那麼在編譯的時候就會有一個預設的轉換操作:將該構造函數對應數據類型的數據轉換為該類對象。也就是說 “CxString string2 = 10;” 這段代碼,編譯器自動將整型轉換為CxString類對象,實際上等同於下麵的操作:

CxString string2(10);  
// 或如下代碼
CxString temp(10);  
CxString string2 = temp;  

但是,上面的代碼中的_size代表的是字元串記憶體分配的大小,那麼調用的第二句 “CxString string2 = 10;” 和第六句 “CxString string6 = ‘c’;” 就顯得不倫不類,而且容易讓人疑惑。有什麼辦法阻止這種用法呢?答案就是使用explicit關鍵字。我們把上面的代碼修改一下,如下:

class CxString  // 使用關鍵字explicit的類聲明, 顯示轉換  
{  
public:  
    char *_pstr;  
    int _size;  
    explicit CxString(int size)  
    {  
        _size = size;  
        // 代碼同上, 省略...  
    }  
    CxString(const char *p)  
    {  
        // 代碼同上, 省略...  
    }  
};  
  
    // 下麵是調用:  
    CxString string1(24);     // 這樣是OK的  
    CxString string2 = 10;    // 這樣是不行的, 因為explicit關鍵字取消了隱式轉換  
    CxString string3;         // 這樣是不行的, 因為沒有預設構造函數  
    CxString string4("aaaa"); // 這樣是OK的  
    CxString string5 = "bbb"; // 這樣也是OK的, 調用的是CxString(const char *p)  
    CxString string6 = 'c';   // 這樣是不行的, 其實調用的是CxString(int size), 且size等於'c'的ascii碼, 但explicit關鍵字取消了隱式轉換  
    string1 = 2;              // 這樣也是不行的, 因為取消了隱式轉換  
    string2 = 3;              // 這樣也是不行的, 因為取消了隱式轉換  
    string3 = string1;        // 這樣也是不行的, 因為取消了隱式轉換, 除非類實現操作符"="的重載 

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

如上面所說, explicit關鍵字只對有一個參數的類構造函數有效,如果類構造函數參數大於或等於兩個時,是不會產生隱式轉換的,所以explicit關鍵字也就無效了。例如:

class CxString  // explicit關鍵字在類構造函數參數大於或等於兩個時無效  
{  
public:  
    char *_pstr;  
    int _age;  
    int _size;  
    explicit CxString(int age, int size)  
    {  
        _age = age;  
        _size = size;  
        // 代碼同上, 省略...  
    }  
    CxString(const char *p)  
    {  
        // 代碼同上, 省略...  
    }  
};  
  
    // 這個時候有沒有explicit關鍵字都是一樣的  

但是, 也有一個例外, 就是當除了第一個參數以外的其他參數都有預設值的時候, explicit關鍵字依然有效, 此時, 當調用構造函數時只傳入一個參數, 等效於只有一個參數的類構造函數, 例子如下:

class CxString  // 使用關鍵字explicit聲明  
{  
public:  
    int _age;  
    int _size;  
    explicit CxString(int age, int size = 0)  
    {  
        _age = age;  
        _size = size;  
        // 代碼同上, 省略...  
    }  
    CxString(const char *p)  
    {  
        // 代碼同上, 省略...  
    }  
};  
  
    // 下麵是調用:  
    CxString string1(24);     // 這樣是OK的  
    CxString string2 = 10;    // 這樣是不行的, 因為explicit關鍵字取消了隱式轉換  
    CxString string3;         // 這樣是不行的, 因為沒有預設構造函數  
    string1 = 2;              // 這樣也是不行的, 因為取消了隱式轉換  
    string2 = 3;              // 這樣也是不行的, 因為取消了隱式轉換  
    string3 = string1;        // 這樣也是不行的, 因為取消了隱式轉換, 除非類實現操作符"="的重載

總結:
explicit關鍵字只需用於類內的單參數構造函數前面。由於無參數的構造函數和多參數的構造函數總是顯示調用,這種情況在構造函數前加explicit無意義。

google的c++規範中提到:explicit的優點是可以避免不合時宜的類型變換,缺點無。所以google約定所有單參數的構造函數都必須是顯示的,只有極少數情況下拷貝構造函數可以不聲明稱explicit,例如作為其他類的透明包裝器的類。
effective c++中說:被聲明為explicit的構造函數通常比其non-explicit兄弟更受歡迎。因為它們禁止編譯器執行非預期(往往也不被期望)的類型轉換。除非我有一個好理由允許構造函數被用於隱式類型轉換,否則我會把它聲明為explicit,鼓勵大家遵循相同的政策。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • L1-087 機工士姆斯塔迪奧 分數 20 全屏瀏覽題目 切換佈局 作者 DAI, Longao 單位 杭州百騰教育科技有限公司 在 MMORPG《最終幻想14》的副本“樂欲之所甌博訥修道院”里,BOSS 機工士姆斯塔迪奧將會接受玩家的挑戰。 你需要處理這個副本其中的一個機制:N×M 大小的地圖被拆 ...
  • 功能實現03 9.功能08-分頁顯示 9.1需求分析 將查詢的數據進行分頁顯示,要求功能如下: 顯示共多少條記錄 可以設置每頁顯示幾條 點擊第幾頁,顯示對應的數據 9.2思路分析 後端使用MyBatisPlus分頁插件完成查詢 修改FurnController,增加處理分頁顯示代碼 完成前臺代碼,加 ...
  • 官網:https://doc.cfd.direct/openfoam/user-guide-v9/platehole $FOAM_TUTORIALS/stressAnalysis/solidDisplacementFoam下的案例 1、網格劃分 /* *- C++ -* *\ | \\ / F ie ...
  • Spring Boot整合Google Bard - Web介面訪問Google AI聊天機器人 之前開發了一個關於Google Bard的Java庫,可以幫助我們簡單的提問並獲得答案。現在我把它整合到Spring Boot應用中,通過Web API讓大家可以訪問。 添加依賴 把pkslow goo ...
  • React Router 備忘清單 IT寶庫整理的React Router開發速查清單適合初學者的綜合 React Router 6.x 備忘清單入門,為開發人員分享快速參考備忘單。 開發速查表大綱 入門 安裝使用 添加路由器 根路由 處理未找到錯誤 contacts 用戶界面 嵌套路由 客戶端路由 ...
  • Redis 備忘清單 IT寶庫整理的Redis開發速查備忘清單 - 本備忘單旨在快速理解 redis 所涉及的主要概念,提供了最常用的SQL語句,供您參考。入門,為開發人員分享快速參考備忘單。 開發速查表大綱 入門 介紹 小試 數據類型 Redis服務相關的命令設置 COMMAND 一些引用(可能有 ...
  • 事件系統 文章為本人理解,如有理解不到位之處,煩請各位指正。 @ Qt的事件迴圈,應該是所有Qter都避不開的一個點,所以,這篇博客,咱們來瞭解源碼中一些關於Qt中事件迴圈的部分。 先拋出幾個疑問,根據源代碼,下麵一一進行解析。 事件迴圈是什麼? 事件是怎麼產生的? 事件是如何處理的? 什麼是事件循 ...
  • 自2022年11月30日 OpenAI 發佈 ChatGPT 以來,雖然時有唱衰的聲音出現,但在OpenAI不斷推陳出新,陸續發佈了OpenAPI、GPT-4、ChatGPT Plugins之後,似乎讓大家看到了一個聊天機器人往操作系統入口進軍的升緯之路。 ChatGPT能被認為是操作系統級別的入口 ...
一周排行
    -Advertisement-
    Play Games
  • 下麵是一個標準的IDistributedCache用例: public class SomeService(IDistributedCache cache) { public async Task<SomeInformation> GetSomeInformationAsync (string na ...
  • 這個庫提供了在啟動期間實例化已註冊的單例,而不是在首次使用它時實例化。 單例通常在首次使用時創建,這可能會導致響應傳入請求的延遲高於平時。在註冊時創建實例有助於防止第一次Request請求的SLA 以往我們要在註冊的時候實例單例可能會這樣寫: //註冊: services.AddSingleton< ...
  • 最近公司的很多項目都要改單點登錄了,不過大部分都還沒敲定,目前立刻要做的就只有一個比較老的項目 先改一個試試手,主要目標就是最短最快實現功能 首先因為要保留原登錄方式,所以頁面上的改動就是在原來登錄頁面下加一個SSO登錄入口 用超鏈接寫的入口,頁面改造後如下圖: 其中超鏈接的 href="Staff ...
  • Like運算符很好用,特別是它所提供的其中*、?這兩種通配符,在Windows文件系統和各類項目中運用非常廣泛。 但Like運算符僅在VB中支持,在C#中,如何實現呢? 以下是關於LikeString的四種實現方式,其中第四種為Regex正則表達式實現,且在.NET Standard 2.0及以上平... ...
  • 一:背景 1. 講故事 前些天有位朋友找到我,說他們的程式記憶體會偶發性暴漲,自己分析了下是非托管記憶體問題,讓我幫忙看下怎麼回事?哈哈,看到這個dump我還是非常有興趣的,居然還有這種游戲幣自助機類型的程式,下次去大玩家看看他們出幣的機器後端是不是C#寫的?由於dump是linux上的程式,剛好win ...
  • 前言 大家好,我是老馬。很高興遇到你。 我們為 java 開發者實現了 java 版本的 nginx https://github.com/houbb/nginx4j 如果你想知道 servlet 如何處理的,可以參考我的另一個項目: 手寫從零實現簡易版 tomcat minicat 手寫 ngin ...
  • 上一次的介紹,主要圍繞如何統一去捕獲異常,以及為每一種異常添加自己的Mapper實現,並且我們知道,當在ExceptionMapper中返回非200的Response,不支持application/json的響應類型,而是寫死的text/plain類型。 Filter為二方包異常手動捕獲 參考:ht ...
  • 大家好,我是R哥。 今天分享一個爽飛了的面試輔導 case: 這個杭州兄弟空窗期 1 個月+,面試了 6 家公司 0 Offer,不知道問題出在哪,難道是杭州的 IT 崩盤了麽? 報名面試輔導後,經過一個多月的輔導打磨,現在成功入職某上市公司,漲薪 30%+,955 工作制,不咋加班,還不捲。 其他 ...
  • 引入依賴 <!--Freemarker wls--> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.30</version> </dependency> ...
  • 你應如何運行程式 互動式命令模式 開始一個互動式會話 一般是在操作系統命令行下輸入python,且不帶任何參數 系統路徑 如果沒有設置系統的PATH環境變數來包括Python的安裝路徑,可能需要機器上Python可執行文件的完整路徑來代替python 運行的位置:代碼位置 不要輸入的內容:提示符和註 ...