[C++] Thorough Explanation of the 4 Types of Casts (static_cast, dynamic_cast, etc.)

目次

Introduction

In C++, four different cast operators are provided to perform explicit type conversion (casting), such as converting an int to a double, or a parent class pointer to a child class pointer. These are safer than the old C-style cast (type)value because their purpose is clearer and compiler checks are stricter.

In this article, I will explain the roles and correct usage of the four main cast operators:

  1. static_cast: Static type conversion
  2. dynamic_cast: Dynamic type conversion (Safe downcast)
  3. const_cast: Changing const/volatile qualifiers
  4. reinterpret_cast: The most dangerous, bit-level reinterpretation

1. static_cast

static_cast is used for the most common conversions where safety can be determined at compile time, such as conversions between numeric types or pointer/reference conversions between classes in an inheritance relationship (upcast/downcast).

#include <iostream>

struct Base {};
struct Derived : Base {};

int main() {
    // 1. Conversion between numeric types
    double pi = 3.14;
    int integer_pi = static_cast<int>(pi); // double -> int
    std::cout << "Converted to int: " << integer_pi << std::endl;

    // 2. Pointer conversion between inheritance relationships
    Derived d;
    // Upcast (Child -> Parent) is safe, so static_cast is OK
    Base* p_base = static_cast<Base*>(&d);
    
    // Downcast (Parent -> Child) is dangerous but allowed at the programmer's risk
    Derived* p_derived = static_cast<Derived*>(p_base);
    
    return 0;
}

Note: Downcasting with static_cast (Parent pointer -> Child pointer) does not check at runtime whether the pointer actually points to an object of that child class. If it is wrong, it causes undefined behavior.

2. dynamic_cast

dynamic_cast performs pointer/reference conversions between classes in an inheritance relationship while checking type safety at runtime. It is mainly used for safe downcasting.

#include <iostream>

// Must have virtual functions to enable RTTI
struct Base { virtual ~Base() {} };
struct Derived : Base {};
struct Another : Base {};

int main() {
    Derived d;
    Base* p_base = &d;

    // 1. Successful downcast
    if (Derived* p_derived = dynamic_cast<Derived*>(p_base)) {
        std::cout << "Downcast to Derived succeeded" << std::endl;
    }
    
    // 2. Failed downcast
    if (Another* p_another = dynamic_cast<Another*>(p_base)) {
        // This block is not executed
    } else {
        std::cout << "Downcast to Another failed (Result is nullptr)" << std::endl;
    }

    return 0;
}

Explanation:

  • dynamic_cast can only be used on polymorphic classes that have at least one virtual function.
  • If the downcast succeeds, it returns a valid pointer.
  • If it fails, it returns nullptr for pointers, or throws a std::bad_cast exception for references.

3. const_cast

const_cast is a special cast used solely to add or remove const or volatile qualifiers.

void print_message(char* str) { std::cout << str << std::endl; }

int main() {
    const char* message = "Hello";
    // print_message requires a non-const pointer
    // Use const_cast to remove const
    print_message(const_cast<char*>(message));
    return 0;
}

Warning: Using const_cast to remove const from an object that was originally defined as const and then attempting to modify its value is undefined behavior and very dangerous.

4. reinterpret_cast

reinterpret_cast is the most dangerous cast. It forcibly reinterprets type information while keeping the bit pattern exactly the same, such as converting a pointer type to a completely unrelated pointer type.

#include <cstdint>
#include <iostream>

int main() {
    long long value = 0x41424344; // "DCBA" in ASCII
    
    // Reinterpret the address of long long as a pointer to char
    char* p_char = reinterpret_cast<char*>(&value);
    
    // Output depends on the environment (endianness), but the first byte ("D") might be output
    std::cout << *p_char << std::endl;

    return 0;
}

Note: This cast should only be used in extremely limited situations, such as low-level interactions with the OS.

Summary

CastMain UsageSafety
static_castGeneral type conversion, safe upcastCompile-time check
dynamic_castSafe downcastRuntime check
const_castChanging const/volatile qualifiersLow (Caution required)
reinterpret_castBit-level reinterpretationExtremely Low (Avoid in principle)

In C++, using these four casts appropriately clarifies the intent of the type conversion and increases code safety.

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次