C++構(gòu)造函數(shù)中explicit詳解
在 C++ 編程中,構(gòu)造函數(shù)是類的核心部分之一。我們常常使用構(gòu)造函數(shù)來初始化對象。但是,如果不加限制,某些構(gòu)造函數(shù)可能會被 隱式調(diào)用,從而帶來一些意料之外的行為。
為了解決這個問題,C++ 提供了 explicit 關(guān)鍵字。
1. 什么是explicit
在 C++ 中,explicit 關(guān)鍵字用于修飾 單參數(shù)構(gòu)造函數(shù) 或 可以看作單參數(shù)的構(gòu)造函數(shù),阻止編譯器進行 隱式類型轉(zhuǎn)換 或 拷貝初始化。
- 默認情況下,單參數(shù)構(gòu)造函數(shù)既可以顯式調(diào)用,也可以被編譯器用來進行隱式類型轉(zhuǎn)換。
explicit告訴編譯器:這個構(gòu)造函數(shù)只能顯式調(diào)用,不能用于隱式轉(zhuǎn)換。
2. 隱式轉(zhuǎn)換的問題
來看一個例子:
#include <iostream>
using namespace std;
class Fraction {
private:
int numerator;
int denominator;
public:
Fraction(int num, int den = 1) : numerator(num), denominator(den) {}
void print() const {
cout << numerator << "/" << denominator << endl;
}
};
int main() {
Fraction f1 = 5; // 隱式調(diào)用 Fraction(5, 1)
f1.print(); // 輸出:5/1
}
在上面的例子中:
Fraction f1 = 5;本質(zhì)上是調(diào)用Fraction(5, 1),因為編譯器允許用int隱式轉(zhuǎn)換成Fraction。- 雖然看似方便,但有時會帶來 不可控的隱式轉(zhuǎn)換,導(dǎo)致邏輯錯誤或二義性。
3.explicit的使用示例
基本用法
如果我們在構(gòu)造函數(shù)前加上 explicit:
class Fraction {
private:
int numerator;
int denominator;
public:
explicit Fraction(int num, int den = 1) : numerator(num), denominator(den) {}
void print() const {
cout << numerator << "/" << denominator << endl;
}
};
int main() {
Fraction f1(5); // ? 顯式調(diào)用,可以
// Fraction f2 = 5; // ? 編譯錯誤,不能隱式轉(zhuǎn)換
}
Fraction f1(5);依然可以顯式調(diào)用。- 但
Fraction f2 = 5;會報錯,因為explicit禁止了隱式轉(zhuǎn)換。
多參數(shù)構(gòu)造函數(shù)
有時構(gòu)造函數(shù)有多個參數(shù),但如果除第一個外的參數(shù)都有默認值,它依然算作 單參數(shù)構(gòu)造函數(shù),也可能引發(fā)隱式轉(zhuǎn)換。
class Fraction {
public:
explicit Fraction(int num, int den = 1) { /* ... */ }
};
這里如果沒有 explicit,表達式 Fraction f = 5; 依然會成立。
4. C++11 之后的擴展
(1)explicit用于轉(zhuǎn)換運算符
在 C++11 之前,類的類型轉(zhuǎn)換函數(shù)(比如 operator bool)會允許隱式轉(zhuǎn)換:
class Test {
public:
operator bool() const { return true; }
};
int main() {
Test t;
if (t) { // 隱式調(diào)用 operator bool()
cout << "True" << endl;
}
}
但有時我們并不希望這種隱式轉(zhuǎn)換。C++11 允許寫成:
class Test {
public:
explicit operator bool() const { return true; }
};
int main() {
Test t;
// if (t) { } // ? 錯誤,不能隱式轉(zhuǎn)換
if (static_cast<bool>(t)) { // ? 必須顯式轉(zhuǎn)換
cout << "True" << endl;
}
}
(2) C++20 的explicit(bool)
C++20 引入了更靈活的語法:explicit(bool)。
這讓我們可以根據(jù)編譯期常量決定是否允許隱式調(diào)用。
struct A {
explicit(true) A(int) {} // 永遠顯式
explicit(false) A(double) {} // 永遠允許隱式
};
這種寫法在模板編程中很有用。
5. 最佳實踐
幾乎總是給單參數(shù)構(gòu)造函數(shù)加
explicit
這樣可以避免隱式轉(zhuǎn)換帶來的混亂,除非你確實需要這種轉(zhuǎn)換。轉(zhuǎn)換運算符應(yīng)當盡量顯式
尤其是operator bool,因為隱式轉(zhuǎn)換到bool可能導(dǎo)致奇怪的條件判斷。允許隱式轉(zhuǎn)換的場景
如果你的類本質(zhì)上就是包裝某個類型(比如string_view可以從const char*隱式轉(zhuǎn)換),那么允許隱式轉(zhuǎn)換可以讓使用更加自然。
總結(jié)
- explicit 的主要作用:防止構(gòu)造函數(shù)或轉(zhuǎn)換運算符被隱式調(diào)用。
- 在單參數(shù)構(gòu)造函數(shù)和轉(zhuǎn)換運算符中使用最為常見。
- 自 C++11 起,還能用于 operator bool;C++20 引入 explicit(bool),進一步增強靈活性。
- 最佳實踐:默認加上 explicit,除非你有充分理由允許隱式轉(zhuǎn)換。
- 關(guān)鍵字explicit只對一個實參的構(gòu)造函數(shù)有效,需要多個實參的構(gòu)造函數(shù)不能用于執(zhí)行隱式轉(zhuǎn)換,所以無需將這些構(gòu)造函數(shù)指定為explicit的。
- 只能在類內(nèi)聲明構(gòu)造函數(shù)時使用explicit關(guān)鍵字。
補充
- 接受一個單參數(shù)的const char*的string構(gòu)造函數(shù)不是explicit的
- 接受一個容量參數(shù)的vector構(gòu)造函數(shù)是explicit的
到此這篇關(guān)于C++構(gòu)造函數(shù)中explicit詳解的文章就介紹到這了,更多相關(guān)C++構(gòu)造函數(shù)explicit內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于C語言實現(xiàn)簡單的12306火車售票系統(tǒng)
火車售票系統(tǒng)給我們的出行帶來了極大的方面,那么他基于編程是如何實現(xiàn)的呢?今天小編抽時間給大家分享一個使用C語言寫的一個簡單的火車票系統(tǒng),感興趣的朋友參考下2016-09-09
使用C語言遞歸與非遞歸實現(xiàn)字符串反轉(zhuǎn)函數(shù)char *reverse(char *str)的方法
本篇文章是對使用C語言遞歸與非遞歸實現(xiàn)字符串反轉(zhuǎn)函數(shù)char *reverse(char *str)進行了詳細的分析介紹,需要的朋友參考下2013-05-05

