【C++】4種類のキャストを徹底解説 (static_cast, dynamic_cast 等)

目次

はじめに

C++には、intからdoubleへ、あるいは親クラスのポインタから子クラスのポインタへ、といった**明示的な型変換(キャスト)**を行うための、4つの異なるキャスト演算子が用意されています。これらは、古いC言語スタイルのキャスト (type)value よりも、目的が明確で、コンパイル時のチェックが厳密であるため、より安全です。

この記事では、4つの主要なキャスト演算子について、それぞれの役割と正しい使い方を解説します。

  1. static_cast: 静的な型変換
  2. dynamic_cast: 動的な型変換(安全なダウンキャスト)
  3. const_cast: const/volatile修飾子の変更
  4. reinterpret_cast: 最も危険な、ビットレベルの再解釈

1. static_cast

static_castは、数値型同士の変換や、継承関係にあるクラス間のポインタ/参照の変換(アップキャスト/ダウンキャスト)など、コンパイル時に安全性が判断できる、最も一般的な変換に使います。

サンプルコード

#include <iostream>

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

int main() {
    // 1. 数値型間の変換
    double pi = 3.14;
    int integer_pi = static_cast<int>(pi); // double -> int
    std::cout << "intに変換: " << integer_pi << std::endl;

    // 2. 継承関係間のポインタ変換
    Derived d;
    // アップキャスト (子 -> 親) は安全なので、static_castでOK
    Base* p_base = static_cast<Base*>(&d);
    
    // ダウンキャスト (親 -> 子) は危険だが、プログラマの責任で許可される
    Derived* p_derived = static_cast<Derived*>(p_base);
    
    return 0;
}

注意: static_castによるダウンキャスト(親ポインタ→子ポインタ)は、ポインタが本当にその子クラスのオブジェクトを指しているかを実行時にはチェックしません。もし間違っていれば、未定義の動作を引き起こします。


2. dynamic_cast

dynamic_castは、継承関係にあるクラス間のポインタ/参照の変換で、実行時に型の安全性をチェックします。主に、安全なダウンキャストのために使われます。

サンプルコード

#include <iostream>

// RTTIを有効にするため、仮想関数を持つ必要がある
struct Base { virtual ~Base() {} };
struct Derived : Base {};
struct Another : Base {};

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

    // 1. 成功するダウンキャスト
    if (Derived* p_derived = dynamic_cast<Derived*>(p_base)) {
        std::cout << "Derivedへのダウンキャスト成功" << std::endl;
    }
    
    // 2. 失敗するダウンキャスト
    if (Another* p_another = dynamic_cast<Another*>(p_base)) {
        // このブロックは実行されない
    } else {
        std::cout << "Anotherへのダウンキャスト失敗 (結果はnullptr)" << std::endl;
    }

    return 0;
}

解説:

  • dynamic_castは、仮想関数を一つ以上持つポリモーフィックなクラスにしか使えません。
  • ダウンキャストに成功すれば、有効なポインタを返します。
  • 失敗した場合、ポインタの場合は nullptr を、参照の場合は std::bad_cast例外をスローします。

3. const_cast

const_castは、const修飾子やvolatile修飾子を追加または削除するためだけに使う、特殊なキャストです。

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

int main() {
    const char* message = "Hello";
    // print_messageは const でないポインタを要求する
    // constを外すためにconst_castを使う
    print_message(const_cast<char*>(message));
    return 0;
}

注意: constとして定義されたオブジェクトのconst性をconst_castで外して、その値を変更しようとする行為は未定義の動作であり、非常に危険です。


4. reinterpret_cast

reinterpret_castは、あるポインタ型を、全く関係のない別のポインタ型に変換するなど、ビットパターンをそのままに、型情報だけを無理やり再解釈する、最も危険なキャストです。

#include <cstdint>

int main() {
    long long value = 0x41424344; // ASCIIで "DCBA"
    
    // long longのアドレスを、charへのポインタとして再解釈
    char* p_char = reinterpret_cast<char*>(&value);
    
    // 環境(エンディアン)に依存するが、先頭バイト("D")が出力される可能性がある
    std::cout << *p_char << std::endl;

    return 0;
}

注意: このキャストは、OSとの低レベルなやり取りなど、極めて限定的な状況でしか使われるべきではありません。


まとめ

キャスト主な用途安全性
static_cast一般的な型変換、安全なアップキャストコンパイル時チェック
dynamic_cast安全なダウンキャスト実行時チェックあり
const_castconst/volatile修飾子の変更低(注意が必要)
reinterpret_castビットレベルの再解釈極めて低(原則使用禁止)

C++では、これらの4つのキャストを適切に使い分けることで、型変換の意図を明確にし、コードの安全性を高めることができます。

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

この記事を書いた人

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

目次