C++ Casting === C++ 中有四種 Cast:`const_cast`、`static_cast`、`dynamic_cast`、`reinterpret_cast`,這些 cast function 不是 marco 也不屬於 STL Libray,是 C++ 的保留字(Keyword)。 ## const_cast const_cast 的用途是移除 const 的屬性。 強烈建議不要用,除非有必須。 用法:`const_cast<T>(ptr)`,其中 ptr 必為指標或 refrence 範例如下: 1. 移除 a 的 const 屬性,並且修改 a 的值 ```cpp const int a = 10; const int *ptr = &a; int *cc = const_cast<int *>(ptr); *cc = 99; std::cout << "*a = " << *a << "\n"; std::cout << "*ptr = " << *ptr << "\n"; std::cout << "*cc = " << *cc << "\n"; // output: // *a = 99 // *ptr = 99 // *cc = 99 ``` 2. 將 const int* 的參數型別改成 int* ```cpp void foo(int *var) { ... } int main() { const int a = 19; const int *ptr = &a; foo(ptr); // Compile Error foo(const_cast<int*>(ptr)); // Valid } ``` ## static_cast 執行於 compile-time,功能與 C-Style cast 相似,但更安全。 範例: 1. 特別標注 c-style cast (implicit cast),增加可讀性及提醒 reader ```cpp float f = 3.5; int n1 = (int)f; int n2 = static_cast<int>(f); // n1 = n2 = 3 ``` 2. 避免不合理的型別轉換 ```cpp char c = 'a'; int *ptr1 = (int *)&c; // sizeof(char) = 1 byte, // sizeof(int*) = 4 byte // This is valid but dangerous since it'll access undefined memory block. *ptr = 1; // c = ??? // *ptr = 1 int *ptr2 = static_cast<int*>(c); // Compile Error ``` ```cpp class Base {}; class Child : private Base {}; int main() { Child child; Base *ptr1 = (Base*)&child; // Allowed at compile-time Base *ptr2 = static_cast<Base*>(child) // Compile Error // Can't access private base class } ``` 3. 任何用到 void* 的時機 ```cpp int n = 10; void *v = static_cast<void*>(&n); int *ip = static_cast<int*>(v); ``` ## dynamic_cast 執行於 run-time,用於 polymorphism,up cast (Derived -> Base) 或 down cast (Base -> Derived)。 若已知型別轉換不會出錯,建議使用 static_cast,執行時間較快。 範例: 1. 檢查繼承關係是否正確 ```cpp class Base { virtual void foo(){}; }; class Derived1 : public Base {}; class Derived2 : public Base {}; int main() { Derived1 d1; // Valid Base *pBase = dynamic_cast<Base*>(d1); Derived1 *pd1 = dynamic_cast<Derived1*>(pBase); Derived2 *pd2 = dynamic_cast<Derived2*>(d1); // pd2 is a nullptr } ``` ## reinterpret_cast 是個很危險的存在,有不可兼容的危險(importable)。 用途是強制轉換型別,不論資料大小是否相同。 範例: ```cpp struct S { int x, // 4 byte int y, // 4 byte char c, // { 4 byte bool b // } }; int main() { S s = { 1, 2, 'a', true }; int *pInt = reinterpret_cast<int*>(&s); std::cout << *pInt << "\n"; // 1 pInt++; std::cout << *pInt << "\n"; // 2 pInt++; char *pChar = reinterpret_cast<char*>(pInt); std::cout << *pChar << "\n"; // a pChar++; bool *pBool = reinterpret_cast<bool*>(pChar); std::cout << *pBool << "\n"; // 1 } ```