物件常需轉換為底層型別 (如 std::string → const char*,fstream → 檔案描述符)。但不經意的隱式轉換會導致驚人的 bug。如何在保留便利性的同時,嚴守型別安全?
USDdoubleclass USD {
__int64 dollars;
int cents;
public:
USD(__int64 d=0, int c=0) : dollars(d), cents(c) {}
// 隱式轉換運算子
operator double() {
double temp = (dollars * 100) + cents;
return temp / 100;
}
};
使用便利:
USD payment(203, 67); // $203.67
double res = payment * 1.05; // 自動轉換 → 213.8535 ✅
payment = payment * 1.05; // ❌ 結果變成 $213.00 (丟失美分!)
原因剖析:
payment * 1.05 觸發轉換運算子 → double 213.8535。payment = 213.8535 需轉換回 USD。USD(__int64(213.8535), 0) → dollars=213, cents=0。explicit 建構子——阻擋隱式建構class USD {
// ...
public:
explicit USD(__int64 d=0, int c=0) : dollars(d), cents(c) {} // 禁止隱式建構
// ...
};
效果:
payment = USD(payment * 1.05); // ✅ 顯式建構,編譯通過
payment = payment * 1.05; // ❌ 編譯錯誤:無隱式建構路徑
double 建構子——正確處理小數class USD {
// ...
public:
explicit USD(double val) {
dollars = static_cast<__int64>(val); // 整數部分
long double temp = (val - dollars) * 100; // 小數部分 ×100
cents = static_cast<int>(temp + 0.5); // 四捨五入避免截斷誤差
}
};
現在 USD(payment * 1.05) 正確構造 $213.85 (四捨五入)。
std::string 無 const char* 轉換運算子,強制用 .c_str(),避免 C API 混用導致 bug。fstream 有 operator void*() (或 explicit operator bool() C++11),支援 if (inf) 判斷流狀態,風險可控。| 決策 | 手段 | 適用場景 |
|---|---|---|
| 允許安全、無損、語義清晰的轉換 | 提供轉換運算子 operator TargetType() | 智慧指標 operator bool()、容器 operator size_type() |
| 禁止隱式建構/賦值導致語義改變 | 建構子標記 explicit | 單參數建構子、數值型別包裝器 |
| 提供精確、可控的轉換路徑 | 額外提供 explicit 建構子或具名函數 .to_xxx() | 浮點↔定點、字串編碼轉換 |
explicit operator bool():顯式轉換運算子,僅在布林語境 (if, while, !) 隱式觸發,其他場合需 static_cast,完美解決「安全布林判斷」需求。= delete:徹底禁用特定轉換/建構路徑。掌握轉換運算子與 explicit 的配合,即掌握了 C++ 型別系統的「閘門控制權」——讓合法轉換暢通無阻,將危險隱式轉換拒之門外。