【C++】static_castとreinterpret_cast、またdynamic_castの違い

2022-10-05

C++のキャストについてあまりよく知らなかったので調べた。

static_castとreinterpret_cast

まずstatic_castreinterpret_castはどちらも型を強制的に変換するものという認識で、違いがよく分かってなかった。

reinterpret_cast は無条件にポインタを変換するのに対し、 static_cast は変換元と先のクラスが親子関係でなければコンパイルエラーが発生する、という違いがある:

Foo* foo;
static_cast<Bar*>(foo);
// ^^^ error: static_cast from 'Foo *' to 'Bar *', which are not related by inheritance, is not allowed
reinterpret_cast<Bar*>(foo); // こちらはコンパイルが通る

ということでどちらかというと static_cast の方が用途が少し制限されている、という違いがある。 言うなれば reinterpret_cast がCのキャストと同じもの。

  • void* からの変換にはどちらも使える
  • コンパイル時に判定するだけなので、実行時には判定や変換処理というものはない
  • どちらも変換後の内容が正しいかどうかは保証されない

多重継承している場合

Base1Base2 を継承した Derived クラスがあったとする。 Derived から Base2 にアップキャストした場合、第1の親クラスじゃないのでポインタがずれる。

その状態から Derived* への static_cast を使用すると、オフセットを考慮してダウンキャストされ、元のポインタが復元できる。

reinterpret_cast では考慮されないので復元はできない(オフセットがずれたまま)。 コンパイルでワーニングが出る:

reinterpret_cast<Derived*>(b2);
// warning: 'reinterpret_cast' to class 'Derived *' from its base at non-zero offset 'Base2 *' behaves differently from 'static_cast' [-Wreinterpret-base-class]
// note: use 'static_cast' to adjust the pointer correctly while downcasting

dynamic_cast

dynamic_cast は通常ダウンキャスト(親クラスから子クラスへの変換)に使用する。 実行時に実際に意図したクラス(またはそれを継承したクラス)かどうかを判定して そうであれば変換し、違ったら nullptr を返す。 実行時型情報(RTTI)を用いるので、仮想関数を持っている必要がある。

多重継承している場合

dynamic_castBase2* から Derived* が復元できる。

const_cast

const_cast はコンパイル時に const ポインタをconstなしポインタとして解釈するよう指示するだけなので、特に不明点はない。