Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C++

dynamic_cast vs static_cast ใน C++: เมื่อไหร่ควรใช้ตัวไหน

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_cast Exception ถ้า 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";
    }
}

ตารางเปรียบเทียบ

Featurestatic_castdynamic_cast
Runtime Check❌ No✅ Yes
PerformanceFast (Compile-time)Slower (RTTI Lookup)
Downcast SafetyUnsafe (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) เร็วกว่าและชัดเจนกว่า