C++ Primer P461 explicit Message(const std::string& str = "") 中的 explicit 禁止單參數構造函數參與隱式類型轉換,避免意外調用導致邏輯錯誤或性能損耗。
class Message {
public:
// 無 explicit
Message(const std::string& str = "") : content(str) {}
std::string content;
};
void printMessage(const Message& msg) {
std::cout << msg.content << std::endl;
}
int main() {
printMessage("Hello"); // 隱式調用 Message("Hello") 創建臨時對象
// 等價於 printMessage(Message("Hello"));
}
編譯器自動將 const char* → std::string → Message,創建臨時對象。若構造函數耗時(讀文件、分配內存),會在不知情下產生開銷。
class Message {
public:
explicit Message(const std::string& str = "") : content(str) {}
// ...
};
void printMessage(const Message& msg);
int main() {
printMessage("Hello"); // 編譯錯誤:無法從 const char* 隱式轉換
printMessage(Message("Hello")); // 必須顯式構造
printMessage(std::string("Hello")); // 或先轉 string
}
| 場景 | 是否加 explicit | 理由 |
|---|---|---|
| 單參數構造函數 | ✅ 默認加 | 防止意外隱式轉換 |
| 多參數構造函數 | ❌ 不需要 | 無法隱式調用(C++11 前) |
| 拷貝/移動構造函數 | ❌ 禁用 | 會導致傳值/返回值失效 |
| 轉換構造函數(有意設計) | ❌ 不加 | 如智能指針從裸指針構造 |
| C++11 列表初始化構造函數 | ✅ 建議加 | 防止 {...} 隱式縮窄轉換 |
class BigInt {
long long val;
public:
BigInt(long long v) : val(v) {}
// 禁止隱式轉換為 bool,但允許顯式轉換
explicit operator bool() const { return val != 0; }
};
void func(bool flag);
BigInt n(42);
if (n) { } // OK: 語境轉換允許 explicit operator bool
func(n); // 錯誤: 隱式轉換被禁止
func((bool)n); // OK: 顯式轉換
func(static_cast(n)); // OK
explicitexplicitexplicit operator Type() 控制外向轉換explicit 含義:**「這個構造函數/轉換函數僅供顯式調用,編譯器不得自動應用」**。C++ Primer 示例中為 Message 加 explicit,防止 const char* 經 std::string 隱式構造 Message 臨時對象,體現「顯式優於隱式」的現代 C++ 設計哲學。