static_cast, dynamic_cast, reinterpret_castの計算結果がすべて違う値になる例がぱっと思いつかなかったのでメモ。
以下のコードは、3つのキャストの計算結果が異なる例である。
#include <iostream>
#include <cstdlib>
class A1 {virtual void f(){};};
class A2 {virtual void g(){};};
class B : public A1, public A2 {};
#define DEBUG_PRINT(val) std::cout << #val << "\t:" << (val) << std::endl
int main(int argc, char* argv[]) {
A2* a2 = new A2;
DEBUG_PRINT(a2);
DEBUG_PRINT(static_cast<B*>(a2));
DEBUG_PRINT(dynamic_cast<B*>(a2));
DEBUG_PRINT(reinterpret_cast<B*>(a2));
delete a2;
return EXIT_SUCCESS;
}
コンパイルして実行すると、以下のように成る。
$ g++ cast_test.cpp
$ ./a.out
a2 :0x55eb8db7ae70
static_cast<B*>(a2) :0x55eb8db7ae68
dynamic_cast<B*>(a2) :0
reinterpret_cast<B*>(a2) :0x55eb8db7ae70
static_cast, dynamic_cast, reinterpret_castの計算結果がそれぞれ異なっている。
static_castでは、元のアドレス値から8を引た値になった。A2とBの継承関係から”8″という値が静的に決められている。実行時は変数の中身を見ないでキャストするので、Bのインスタンスでないa2に対しても構わず引き算を実行している。
dynamic_castでは、実行時にa2の継承関係を調べて結果を決める。a2はBのインスタンスではないので、動的キャストに失敗してnullptrが返る。
reinterpret_castは、計算前後でアドレス値が変化しない1。
reinterpret_castの危険性がよく分かる。
厳密に言うと、
reinterpret_cast前後でアドレス値が変わるかどうかは処理系依存である。C++11では、reintepret_castで別の型に変換して、再度reinterpret_castで元の型に戻しても値が変わらないことだけが記載されている。 ↩︎
