explicit 修飾單一參數建構函數,禁止編譯器執行隱式型別轉換。若無 explicit,編譯器會自動將對應型別轉換為類別物件,這在強型別語言中屬特例行為,易導致非預期轉換。
class MyClass {
public:
MyClass(int num); // 非 explicit
};
MyClass obj = 10; // OK:編譯器隱式轉換 int → MyClass
// 等同於:MyClass temp(10); MyClass obj = temp;
class MyClass {
public:
explicit MyClass(int num); // 顯式建構函數
};
MyClass obj = 10; // 編譯錯誤:cannot convert 'int' to 'MyClass'
// 必須顯式建構:MyClass obj(10); 或 MyClass obj = MyClass(10);
標準庫 std::string 的 string(int size) 若非 explicit,string s = 1; 會被誤解為建立大小 1 的字串,而非字元 '1'。宣告為 explicit string(int) 可攔截此類筆誤。反之,string(const char*) 保留隱式轉換以支援 string s = "hello"; 等自然語法。
若類別有多個建構函數,explicit 僅影響被修飾的那個。編譯器仍會嘗試其他非 explicit 建構函數進行隱式轉換。
class isbn_mismatch : public std::logic_error {
public:
explicit isbn_mismatch(const std::string& s) : std::logic_error(s) {}
isbn_mismatch(const std::string& s, const std::string& lhs, const std::string& rhs)
: std::logic_error(s), left(lhs), right(rhs) {} // 非 explicit
const std::string left, right;
virtual ~isbn_mismatch() throw() {}
};
// 拋出時:throw isbn_mismatch("isbn mismatch", lhs.book(), rhs.book()); // 呼叫非 explicit 版
《ANSI/ISO C++ Professional Programmer's Handbook》建議:單一參數建構函數預設應加 explicit,除非隱式轉換符合領域邏輯且行為良好(如智慧指標、字串字面值轉換)。