static_cast
- used for general type conversions that well-defined and safe.
- performs compile time type checking but does not perform runtime type checking.
- can be used for implicit conversions, numeric conversions, upcasting, downcasting(if the relationship is known at compile time).
enum class E { ONE = 1, TWO, THREE };
// scoped enum to int
E e = E::TWO;
int two = static_cast<int>(e);
const_cast
- used to add or remove the const or volatile qualifiers from a variable.
- can be used to modify non-const variables through a pointer or reference to const
int i = 3; // i is not declared const
const int& rci = i;
const_cast<int&>(rci) = 4; // OK: modifies i
dynamic_cast
- used for safe downcasting and runtime type checking in the context of polymorphic classes
- perform runtime type checking and returns a null pointer if the conversion is not possible(when casting pointers) or throws a std::bad_cast exception(when casting reference).
- checks if the casted object's type is compatible with the target type.
struct V {};
struct A : virtual V{};
struct B : virtual V{};
struct D : A, B {};
D d; // the most derived object
A& a = d; // upcast, dynamic_cast may be used, but unnecessary
D& new_d = dynamic_cast<D&>(a); // downcast
B& new_b = dynamic_cast<B&>(a); // sidecast
reinterpret_cast
- used for low-level, unsafe conversions between unrelated types.
- No type checking is performed, and result may not be meaningful or well-defined.
- use with extrem caution, it can easily lead to undefined behavior.
int i = 7;
// type aliasing through pointer
char* p2 = reinterpret_cast<char*>(&i);