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
  • Dapr Outbox 是1.12中的功能。 本文只介紹Dapr Outbox 執行流程,Dapr Outbox基本用法請閱讀官方文檔 。本文中appID=order-processor,topic=orders 本文前提知識:熟悉Dapr狀態管理、Dapr發佈訂閱和Outbox 模式。 Outbo ...
  • 引言 在前幾章我們深度講解了單元測試和集成測試的基礎知識,這一章我們來講解一下代碼覆蓋率,代碼覆蓋率是單元測試運行的度量值,覆蓋率通常以百分比表示,用於衡量代碼被測試覆蓋的程度,幫助開發人員評估測試用例的質量和代碼的健壯性。常見的覆蓋率包括語句覆蓋率(Line Coverage)、分支覆蓋率(Bra ...
  • 前言 本文介紹瞭如何使用S7.NET庫實現對西門子PLC DB塊數據的讀寫,記錄了使用電腦模擬,模擬PLC,自至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1.Windows環境下鏈路層網路訪問的行業標準工具(WinPcap_4_1_3.exe)下載鏈接:http ...
  • 從依賴倒置原則(Dependency Inversion Principle, DIP)到控制反轉(Inversion of Control, IoC)再到依賴註入(Dependency Injection, DI)的演進過程,我們可以理解為一種逐步抽象和解耦的設計思想。這種思想在C#等面向對象的編 ...
  • 關於Python中的私有屬性和私有方法 Python對於類的成員沒有嚴格的訪問控制限制,這與其他面相對對象語言有區別。關於私有屬性和私有方法,有如下要點: 1、通常我們約定,兩個下劃線開頭的屬性是私有的(private)。其他為公共的(public); 2、類內部可以訪問私有屬性(方法); 3、類外 ...
  • C++ 訪問說明符 訪問說明符是 C++ 中控制類成員(屬性和方法)可訪問性的關鍵字。它們用於封裝類數據並保護其免受意外修改或濫用。 三種訪問說明符: public:允許從類外部的任何地方訪問成員。 private:僅允許在類內部訪問成員。 protected:允許在類內部及其派生類中訪問成員。 示 ...
  • 寫這個隨筆說一下C++的static_cast和dynamic_cast用在子類與父類的指針轉換時的一些事宜。首先,【static_cast,dynamic_cast】【父類指針,子類指針】,兩兩一組,共有4種組合:用 static_cast 父類轉子類、用 static_cast 子類轉父類、使用 ...
  • /******************************************************************************************************** * * * 設計雙向鏈表的介面 * * * * Copyright (c) 2023-2 ...
  • 相信接觸過spring做開發的小伙伴們一定使用過@ComponentScan註解 @ComponentScan("com.wangm.lifecycle") public class AppConfig { } @ComponentScan指定basePackage,將包下的類按照一定規則註冊成Be ...
  • 操作系統 :CentOS 7.6_x64 opensips版本: 2.4.9 python版本:2.7.5 python作為腳本語言,使用起來很方便,查了下opensips的文檔,支持使用python腳本寫邏輯代碼。今天整理下CentOS7環境下opensips2.4.9的python模塊筆記及使用 ...