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émstd::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ểm | static_cast | dynamic_cast |
|---|---|---|
| Thời điểm kiểm tra | Compile-time | Runtime |
| Yêu cầu polymorphic | Không | Có (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ăng | Nhanh (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/volatilereinterpret_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)