In C++, there are four type conversion operators: static_cast, dynamic_cast, const_cast, and reinterpret_cast. They have significant differences in their usage and behavior.
Below, we will detail their differences and applicable scenarios:
1. static_cast (Static Conversion)
Usage: Used for conversions between basic data types and for pointer or reference conversions between classes with an inheritance relationship.
Characteristics:
Performs type checking and conversion at compile time, without runtime type checking.
Can be used for upcasting (from derived class to base class) and downcasting (from base class to derived class), but downcasting does not check for safety, which may lead to undefined behavior.
Can be used for implicit conversions (e.g., int to double) and some explicit conversions (e.g., void* to other pointer types).
double d = 3.14;int i = static_cast<int>(d); // Basic type conversion
class Base {};class Derived : public Base {};
Derived* derived = new Derived;Base* base = static_cast<Base*>(derived); // Upcasting, safe
Base* base2 = new Base;Derived* derived2 = static_cast<Derived*>(base2); // Downcasting, unsafe
2. dynamic_cast (Dynamic Conversion)
Usage: Mainly used for pointer or reference conversions between classes with polymorphism (i.e., classes that contain virtual functions), especially for downcasting and cross-casting.
Characteristics:
Performs type checking at runtime, determining the legality of the conversion through RTTI (Runtime Type Information).
Upcasting behaves the same as static_cast but is safer.
For downcasting, if the conversion is unsafe (e.g., a base class pointer does not actually point to a derived class object), it returns nullptr for pointers and throws std::bad_cast exception for references.
Can only be used with classes that have virtual functions, as RTTI information is stored in the virtual function table.
class Base { virtual void func() {} };class Derived : public Base {};
Base* base = new Derived;Derived* derived = dynamic_cast<Derived*>(base); // Safe downcasting
Base* base2 = new Base;Derived* derived2 = dynamic_cast<Derived*>(base2); // Returns nullptr
// Reference conversionDerived d;Base& base_ref = d;Derived& derived_ref = dynamic_cast<Derived&>(base_ref); // Safe
Base b;Base& base_ref2 = b;try { Derived& derived_ref2 = dynamic_cast<Derived&>(base_ref2); // Throws std::bad_cast} catch (const std::bad_cast& e) { // Handle exception}
3. const_cast (Const Conversion)
Usage: Specifically used to remove or add const or volatile attributes of an object, and can only be used for these two types of conversions.
Characteristics:
Cannot be used for other types of conversions, such as converting int to double.
If const_cast is used to remove the const attribute from an object that is originally const and then modified, it will lead to undefined behavior.
Mainly used in function overloading and certain special scenarios, such as needing to modify an object passed by const reference.
const int a = 10;// int& ref = a; // Error: cannot convert const int& to int&int& ref = const_cast<int*>(a);ref = 20; // Undefined behavior, modified the original const object
void func(const int* ptr) { int* non_const_ptr = const_cast<int*>(ptr); // Legal, but modification may be dangerous}
4. reinterpret_cast (Reinterpretation Conversion)
Usage: Used for conversions between any pointer types and for conversions between pointers and integer types, it is the least safe conversion.
Characteristics:
Does not perform any type checking, simply reinterprets the binary bits.
May lead to non-portable code, as the representation of pointers may differ across systems.
Mainly used in low-level programming, hardware interaction, or specific system programming needs.
int i = 42;int* ptr = &i;long addr = reinterpret_cast<long>(ptr); // Pointer to integer conversion
char* char_ptr = reinterpret_cast<char*>(ptr); // Any pointer type conversion
// Dangerous example: may lead to undefined behaviorstruct Data { int value; };Data* data_ptr = new Data{100};float* float_ptr = reinterpret_cast<float*>(data_ptr);// Accessing Data object using float_ptr will lead to undefined behavior
|
Conversion Operator |
Main Usage |
Type Checking Timing |
Safety |
Convertible Type Range |
|
static_cast |
Basic type conversion, up/down conversion in inheritance |
Compile time |
Partially safe |
Related types |
|
dynamic_cast |
Safe downcasting and cross-casting between polymorphic classes |
Runtime |
Safe |
Classes with virtual functions |
|
const_cast |
Remove or add const/volatile attributes |
Compile time |
Use with caution |
Only modifies constness |
|
reinterpret_cast |
Any pointer type conversion, pointer to integer conversion |
None |
Unsafe |
Any type |
Usage Recommendations
(1) Prefer using static_cast for regular conversions, as it is the safest.
(2) Use dynamic_cast when downcasting between polymorphic classes to ensure runtime safety.
(3) Only use const_cast when necessary, and ensure that the original const object will not be modified.
(4) Avoid using reinterpret_cast as much as possible, as it may lead to non-portable code and undefined behavior; consider using it only in low-level programming.