C++ มี Cast Operators 4 ตัว: static_cast, dynamic_cast, const_cast, reinterpret_cast บทความนี้เน้น static_cast vs dynamic_cast สำหรับ Class Hierarchy
static_cast: Compile-time Cast (No Runtime Check)
- ใช้สำหรับ: Related Types (Base↔Derived), Arithmetic Types, Enum, Void Pointer
- ไม่มี Runtime Check -> Fast แต่ Unsafe หาก Cast ผิด
- Upcast (Derived* → Base*): ปลอดภัยเสมอ (Implicit ได้)
- Downcast (Base* → Derived*): Programmer รับผิดชอบความถูกต้อง
- ไม่สามารถ Cast ระหว่าง Unrelated Classes ได้ (Compile Error)
ตัวอย่าง static_cast
class Base { virtual ~Base() {} };
class Derived : public Base {};
class Unrelated {};
int main() {
Derived* d = new Derived;
Base* b = static_cast<Base*>(d); // OK: Upcast (Implicit ก็ได้)
Derived* d2 = static_cast<Derived*>(b); // OK: Downcast (Programmer Knows)
// Unrelated* u = static_cast<Unrelated*>(d); // Compile Error!
}
dynamic_cast: Runtime Cast (RTTI Required)
- ใช้สำหรับ: Polymorphic Downcast (Base* → Derived*) และ Cross-Cast
- ต้องมี Virtual Function อย่างน้อย 1 ตัวใน Base (RTTI)
- มี Runtime Check -> Safe แต่ช้ากว่า
- Pointer: คืน
nullptrถ้า Cast ไม่ได้ - Reference: โยน
std::bad_castException ถ้า Cast ไม่ได้
ตัวอย่าง dynamic_cast
#include <iostream>
class Base { public: virtual ~Base() {} virtual void print() { std::cout << "Base\n"; } };
class Derived1 : public Base { public: void print() override { std::cout << "Derived1\n"; } };
class Derived2 : public Base { public: void print() override { std::cout << "Derived2\n"; } };
int main() {
Base* b1 = new Derived1;
Base* b2 = new Base;
// Pointer Version: Return nullptr on Failure
Derived1* d1 = dynamic_cast<Derived1*>(b1); // Success
Derived1* d2 = dynamic_cast<Derived1*>(b2); // Failure -> nullptr
if (d1) d1->print(); // Derived1
if (!d2) std::cout << "Cast failed\n";
// Reference Version: Throw Exception on Failure
try {
Derived2& ref = dynamic_cast<Derived2&>(*b1); // Throws bad_cast
} catch (std::bad_cast&) {
std::cout << "Bad Cast Caught\n";
}
}
ตารางเปรียบเทียบ
| Feature | static_cast | dynamic_cast |
|---|---|---|
| Runtime Check | ❌ No | ✅ Yes |
| Performance | Fast (Compile-time) | Slower (RTTI Lookup) |
| Downcast Safety | Unsafe (UB ถ้าผิด) | Safe (nullptr/Exception) |
| Upcast | ✅ Implicit/Explicit | ✅ Works (แต่ไม่จำเป็น) |
| Cross-Cast (Sibling) | ❌ Compile Error | ✅ Works |
| Requires Virtual | ❌ | ✅ (Polymorphic Class) |
| Void Pointer | ✅ | ❌ |
| Const/Volatile | ✅ (const_cast) | ✅ |
เมื่อไหร่ใช้ตัวไหน?
- static_cast: Upcast, Numeric Conversion, Enum, Void*, Downcast เมื่อแน่ใจ 100% (Performance Critical)
- dynamic_cast: Downcast เมื่อ ไม่แน่ใจ Type จริง, Cross-Cast, Plugin Systems, Type Erasure
- Design Hint: ถ้าต้อง dynamic_cast บ่อย -> ระบบ Design อาจผิด (Violate LSP, ใช้ Virtual Functions แทน)
สรุป
static_cast = Fast, Unsafe Downcast, Compile-time dynamic_cast = Safe, Runtime Check, Polymorphic Only ใช้ dynamic_cast เมื่อจำเป็นต้องตรวจสอบ Type ระหว่าง Runtime มิฉะนั้น static_cast (หรือ Virtual Dispatch) เร็วกว่าและชัดเจนกว่า