見切り発車

とりあえずかきとめたい

C++ のダウンキャストについて考える

今どきのゲーム開発環境を実現しようとするとどうしてもC++ でダウンキャストが必要になってきます。

C++ でダウンキャストを行うにはdynamic_cast を使用するのが通常の手段ですがなかなか重い処理なのでゲームではあまり使いたくない選択肢です。

static_cast でもダウンキャストが可能です。例えばclass B がclass A を継承している場合A からB へのstatic_cast でダウンキャストが可能です。

class A {};
class B : public A {};
class C;
B b;
A * a = &b;
B * pb = static_cast<B *>(a); // OK. 継承関係がある
C * pc = static_cast<C *>(a); // NG. 継承関係がない

dynamic_cast とstatic_cast の違いは、dynamic_cast では実行時型情報を利用してダウンキャストの正当性をチェックするところです。

class A { public: virtual ~A() = default; }
class B : public A{};
class C : public A{};
B b;
A * a = &b;
B * pb = dynamic_cast<B *>(a); // 正しくキャストされる
C * pc = dynamic_cast<C *>(a); // nullptr を返す

pb = static_cast<B *>(a); // 正しくキャストされる
pc = static_cast<C *>(a); // 不正なポインタとなる

dynamic_cast ほどの汎用性は不要という条件であれば、独自に継承関係を解決してやればstatic_cast でそれなりに安全なキャストが可能です。
例えばstatic_cast ではvirtual 継承を使用している場合にはダウンキャストはできませんがそういう使い方はしない、など。
(virtual 継承でなくてもダイヤモンド継承してたらキャストはうまくいかないのでした。)

必要な機能は

  • クラスに静的変数として型の識別子を持たせる
  • インスタンスに型の識別子を持たせる
  • 型の識別子を比較してキャストの正当性を判定する

といったところでしょうか。

これらを実装するときにC++ の機能だけだとわりと定型的な処理を各クラスごとに記述する場面にぶつかります(と予想します)。
こういうのを毎回手書きするのは面倒&エラーのもとになるのでこの辺りの解決策がポイントになりそうです。
解決策は考え中。