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

