0
0
CppComparisonIntermediate · 4 min read

Static_cast vs dynamic_cast vs reinterpret_cast in C++: Key Differences

In C++, static_cast performs compile-time checked conversions between related types, dynamic_cast safely converts polymorphic types at runtime with type checking, and reinterpret_cast performs low-level, unsafe conversions that simply reinterpret the bit pattern of a pointer or reference.
⚖️

Quick Comparison

Here is a quick table summarizing the main differences between static_cast, dynamic_cast, and reinterpret_cast in C++.

Featurestatic_castdynamic_castreinterpret_cast
PurposeConvert related types safely at compile timeConvert polymorphic types safely at runtimeLow-level cast, reinterprets bits without safety
Type CheckingCompile-timeRuntime with RTTINone
Use CaseConversions like int to float, base to derived (if safe)Downcasting in class hierarchies with virtual functionsPointer conversions, type punning
SafetySafe if used correctlySafe, returns nullptr or throws on failureUnsafe, can cause undefined behavior
PerformanceFast, no runtime overheadSlower, involves runtime checksFast, no checks
Requires PolymorphismNoYesNo
⚖️

Key Differences

static_cast is used for conversions between related types known at compile time, such as numeric conversions or up/down casting in inheritance when you are sure about the types. It does not check types at runtime, so misuse can cause undefined behavior.

dynamic_cast is designed for safe downcasting in polymorphic class hierarchies. It uses runtime type information (RTTI) to check if the cast is valid. If the cast fails, it returns nullptr for pointers or throws an exception for references, preventing unsafe conversions.

reinterpret_cast is the most low-level cast. It simply reinterprets the bit pattern of one type as another without any safety checks. It is used for pointer conversions or type punning but can easily cause undefined behavior if misused. It does not require polymorphism or related types.

⚖️

Code Comparison

This example shows how static_cast converts a base class pointer to a derived class pointer when the cast is safe.

cpp
#include <iostream>

class Base {
public:
    virtual void speak() { std::cout << "Base speaking\n"; }
};

class Derived : public Base {
public:
    void speak() override { std::cout << "Derived speaking\n"; }
    void derivedOnly() { std::cout << "Derived only function\n"; }
};

int main() {
    Base* basePtr = new Derived();
    Derived* derivedPtr = static_cast<Derived*>(basePtr); // Safe because basePtr actually points to Derived
    derivedPtr->speak();
    derivedPtr->derivedOnly();
    delete basePtr;
    return 0;
}
Output
Derived speaking Derived only function
↔️

dynamic_cast Equivalent

This example uses dynamic_cast to safely downcast a base class pointer to a derived class pointer with runtime checking.

cpp
#include <iostream>

class Base {
public:
    virtual void speak() { std::cout << "Base speaking\n"; }
    virtual ~Base() = default;
};

class Derived : public Base {
public:
    void speak() override { std::cout << "Derived speaking\n"; }
    void derivedOnly() { std::cout << "Derived only function\n"; }
};

int main() {
    Base* basePtr = new Base();
    Derived* derivedPtr = dynamic_cast<Derived*>(basePtr); // Will be nullptr because basePtr is not Derived
    if (derivedPtr) {
        derivedPtr->speak();
        derivedPtr->derivedOnly();
    } else {
        std::cout << "dynamic_cast failed: basePtr is not a Derived\n";
    }
    delete basePtr;
    return 0;
}
Output
dynamic_cast failed: basePtr is not a Derived
🎯

When to Use Which

Choose static_cast when you know the types are related and the conversion is safe at compile time, such as numeric conversions or upcasting/downcasting without polymorphic checks.

Choose dynamic_cast when you need safe downcasting in polymorphic class hierarchies and want runtime type checking to avoid invalid casts.

Choose reinterpret_cast only for low-level operations like converting between unrelated pointer types or type punning, and be very careful because it can easily cause undefined behavior.

Key Takeaways

static_cast is for compile-time checked conversions between related types.
dynamic_cast safely casts polymorphic types at runtime using RTTI.
reinterpret_cast reinterprets bits without safety and should be used cautiously.
Use dynamic_cast for safe downcasting in class hierarchies with virtual functions.
Avoid reinterpret_cast unless you have a specific low-level need.