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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...