Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> C++

dynamic_cast và static_cast trong C++

Hai toán tử ép kiểu (cast) quan trọng trong C++ cho kế thừa: static_cast (tĩnh, compile-time) và dynamic_cast (động, runtime).

static_cast - Ép kiểu tĩnh

  • Kiểm tra tại compile-time
  • Dùng cho: chuyển kiểu cơ bản, con trỏ lớp cơ sở ↔ dẫn xuất (khi chắc chắn an toàn), enum ↔ int, void* ↔ T*
  • Không kiểm tra runtime → nhanh nhưng không an toàn nếu sai
  • Không thể cast qua virtual inheritance

Ví dụ: Hợp lệ vs Lỗi compile


#include <iostream>

class Base {};
class Derived : public Base {};
class Unrelated {};

int main() {
    Derived* d = new Derived;
    
    // OK: Derived* -> Base* (upcast - luôn an toàn)
    Base* b = static_cast<Base*>(d);
    
    // LỖI COMPILE: Derived* -> Unrelated* (không liên quan)
    // Unrelated* u = static_cast<Unrelated*>(d);
    
    // OK: void* -> Derived* (nếu chắc chắn)
    void* v = d;
    Derived* d2 = static_cast<Derived*>(v);
    
    delete d;
}

dynamic_cast - Ép kiểu động (Runtime)

  • Kiểm tra tại runtime (cần RTTI - Run Time Type Information)
  • Chỉ dùng cho con trỏ/tham chiếu đến lớp có hàm ảo (polymorphic)
  • Downcast (Base* → Derived*): Kiểm tra object thực sự là Derived
  • Cross-cast (Derived1* → Derived2* qua Base): Hỗ trợ
  • Trả về nullptr (con trỏ) hoặc ném std::bad_cast (tham chiếu) nếu thất bại

Ví dụ: Polymorphism với dynamic_cast


#include <iostream>

class Base {
public:
    virtual ~Base() = default;  // Phải có virtual destructor
    virtual void print() const { std::cout << "Base\n"; }
};

class Derived1 : public Base {
public:
    void print() const override { std::cout << "Derived1\n"; }
};

class Derived2 : public Base {
public:
    void print() const override { std::cout << "Derived2\n"; }
};

int main() {
    Base* a = new Derived1;
    Base* b = new Derived2;
    
    a->print();  // Derived1
    b->print();  // Derived2
    
    // Downcast: Base* -> Derived1*
    Derived1* d1 = dynamic_cast<Derived1*>(a);
    if (d1) d1->print();  // Thành công
    
    // Downcast thất bại: Base* (Derived2) -> Derived1*
    Derived1* d1_fail = dynamic_cast<Derived1*>(b);
    if (!d1_fail) std::cout << "Khong the cast Derived2 -> Derived1\n";
    
    // Cross-cast: Derived1* -> Derived2* (qua Base)
    Derived2* d2 = dynamic_cast<Derived2*>(a);  // nullptr
    
    delete a;
    delete b;
}

Kết quả

Derived1
Derived2
Derived1
Khong the cast Derived2 -> Derived1

So sánh chi tiết

Đặc điểmstatic_castdynamic_cast
Thời điểm kiểm traCompile-timeRuntime
Yêu cầu polymorphicKhôngCó (cần virtual function)
Upcast (Derived→Base)✅ An toàn✅ An toàn (nhưng thừa)
Downcast (Base→Derived)⚠️ Nguy hiểm✅ An toàn (trả nullptr nếu sai)
Cross-cast❌ Không✅ Có
Hiệu năngNhanh (zero-cost)Chậm hơn (RTTI lookup)
Void*✅ OK❌ Không

Khi nào dùng cái nào?

  • static_cast: Upcast, chuyển kiểu số, void*, enum, khi bạn chắc chắn kiểu đúng
  • dynamic_cast: Downcast, cross-cast khi không chắc chắn kiểu thực tế
  • Thiết kế tốt: Tránh downcast bằng virtual function/visitor pattern

Các cast khác

  • const_cast: Thêm/bỏ const/volatile
  • reinterpret_cast: Ép kiểu cấp thấp (bit pattern), nguy hiểm
  • C-style cast (Type)expr: Tránh dùng (kết hợp static/const/reinterpret)