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
}
```