C 風格強制轉換 (Type)expr 功能過於強大且隱蔽:同時包含 static_cast、const_cast、reinterpret_cast 三種語義,編譯器不報警、運行期不檢查,極易導致未定義行為。C++98 引入四個具體命名轉換運算符,強制程序員表達意圖、限制轉換範圍、啟用編譯期/運行期檢查。本文深度解析四者語義、適用場景、陷阱與選擇決策樹。
| 運算符 | 核心用途 | 運行期檢查 | 可轉換 const/volatile | 典型風險 |
|---|---|---|---|---|
static_cast | 編譯期可驗證的相關類型轉換:數值、指針上下行、引用、隱式轉換逆向 | 無 | 否 | 下行轉換若對象非目標類型 → UB |
dynamic_cast | 多態層級指針/引用下行/橫向轉換 | 有 (需 RTTI,多態類型) | 否 | 指針轉失敗返回 nullptr;引用轉失敗拋 bad_cast |
const_cast | 移除/添加 const/volatile 資格 | 無 | 唯一合法 | 修改原本 const 對象 → UB |
reinterpret_cast | 位模式重新解釋:指針↔整數、無關指針類型互轉、函數指針互轉 | 無 | 否 | 極度依賴實現,僅轉回原類型安全 |
double → int、int → enum、float → double (窄化轉換編譯器警告)。Derived* → Base* (隱式也可),Derived& → Base&。Base* → Derived* —— 程序員保證對象確實是 Derived,無運行期檢查,錯誤導致 UB。void* → T* (C++ 隱式禁止,需 static_cast)。static_cast(cstr) 。double d = 3.14;
int i = static_cast(d); // 3
Base* pb = new Derived();
Derived* pd = static_cast(pb); // 程序員擔保 pb 指向 Derived
// 若 pb 實際指向 Base → pd 為野指針,解引用 UB
nullptr (不拋異常)。std::bad_cast。virtual 繼承)。dynamic_cast(pb) 返回完整對象起始地址。struct Base { virtual ~Base() {} };
struct Derived : Base {};
Base* pb = new Derived();
Derived* pd = dynamic_cast(pb); // 成功
Base* pb2 = new Base();
Derived* pd2 = dynamic_cast(pb2); // 失敗,返回 nullptr
if (!pd2) std::cout << "Not a Derived\n";
性能:現代實現極快 (單指針比較或緩存),但頻繁熱點路徑仍建議設計避免下行轉換 (Visitor 模式、虛函數分發)。
this),前提是對象原本非 const。const (含字面量、constexpr、只讀內存段) 後通過 const_cast 修改。class TextBlock {
std::string text;
public:
const char& operator[](size_t pos) const { // const 版
return text[pos];
}
char& operator[](size_t pos) { // 非 const 版
return const_cast( // 移除 const
static_cast(*this)[pos] // 調用 const 版
);
}
};
uintptr_t addr = reinterpret_cast(ptr); (哈希、標識、序列化)。int* → char*、ClassA* → ClassB* (無繼承關係)。reinterpret_cast 轉出後,**僅** 轉回原類型使用,否則行為實現定義。// 哈希函數示例
size_t Hash(void* p) {
uintptr_t val = reinterpret_cast(p);
return static_cast(val ^ (val >> 16));
}
// 嚴禁用法
int i = 42;
double* pd = reinterpret_cast(&i); // UB:違反嚴格別名規則,訪問 pd 為 UB
(T)expr 或 T(expr) 按順序嘗試:
const_caststatic_cast (忽略訪問控制,可轉 private 基類)static_cast + const_castreinterpret_castreinterpret_cast + const_cast第一個成功者生效。**極其危險**:可能意外觸發 reinterpret_cast,繞過訪問控制,且無任何語義提示。
const_cast (確認對象非真 const)。dynamic_cast (需虛函數、RTTI)。static_cast。reinterpret_cast (極度謹慎,加註釋說明依賴假設)。gsl::narrow_cast / narrow (Guideline Support Library):窄化轉換運行期斷言/異常。std::bit_cast (C++20):類型大小相同、可平凡拷貝的類型間位模式轉換,**安全替代 reinterpret_cast** (如 float → uint32_t)。static_assert + std::is_convertible / Concepts:編譯期約束轉換合法性。類型轉換是 C++ 類型系統的「逃生艙」,而非常規通道。**原則:盡量不轉換;必須轉換時,用最具體語義的命名轉換,讓意圖可讀、錯誤可查、行為可控**。牢記:dynamic_cast 保命,static_cast 當家,const_cast 專用,reinterpret_cast 避之則吉。