キャストを調べまわってわかった事をメモ
こうですか?分かりません!><
従来のキャストは超危険
- 無条件で変換できちゃう
- そもそもどういった目的でキャストしているのか判らない
- 括弧で括るだけなので、grepで探しづらい
- 設計側としては非推奨
新しいcast
- 目的別にキャストを分ける
- どういった理由でキャストを行っているかわかりやすい
- 危険なキャストを発見しやすい
- 以下の4種類
- dynamic_cast
- static_cast
- reinterpret_cast
- const_cast
dynamic_cast
目的
安全な基底クラスから派生クラスへのキャスト(ダウンキャスト)
キャスト対象
- 基底クラスから派生クラスへのキャスト(ダウンキャスト)
- 派生クラスから基底クラスへのキャスト(アップキャスト)も特に問題なくできるが、そちらはstatic_cast推奨
- 例外が発生しないから
- static_castの方が軽いから→dynamic_castのコスト
- 実体はキャストしない
特徴
- 動的なキャスト(実行時にキャストの可不可をチェックする)
- 駄目なら、エラー処理に移れるので安心して使える
- 実行時、不正ならnullポインタを返却
- 参照のキャストならbad_cast例外をthrow
- 基底クラスはポリモーフィッククラス(仮想関数を持つクラス)であること
- キャスト時に型情報をチェックするRTTI(実行時型情報)がポリモーフィッククラスが持つ仮想関数テーブルに存在するため
- RTTIが仮想関数テーブルにあるのは、全部のオブジェクトに持たせるのはオーバーヘッドになるため
- 仮想関数テーブルを持たないクラスはstatic_castすべきという思想→C++の設計と進化
- キャスト時に型情報をチェックするRTTI(実行時型情報)がポリモーフィッククラスが持つ仮想関数テーブルに存在するため
- 従来のキャストではできなかったクロスキャストや、抽象基底クラスからのダウンキャストも可能
- 詳細はこちら→C++の新しいキャスト
static_cast
目的
危険なキャストをコンパイルエラーではじく事
reinterpret_cast
目的
他のキャストが使えない場合の最終手段
キャスト対象
- ポインタ同士のキャスト
- ポインタと整数型のキャスト
const_cast
目的
constを取り除くことだけ
キャスト対象
- constを持つオブジェクトから、同一の型を持つ非constのオブジェクトへのキャスト
キャストは最終手段
- 本来はポリモーフィズムで回避すべき
- 特定の派生クラスにしかないメソッドを実行したい場合、dynamic_castで判別せずに、基底クラスに何もしないvirtualクラスを作るべき。
悪い例
class Animal { … } class Bird : public Animal { // 飛ぶ処理 void fly() { … } … }
これだと、bridなら飛ぶ場合、余計な分岐が必要になる。
// 飛ぶイベント発生 void event( Animal * amnimal ) { // 鳥なら飛ぶ Bird * bird = dynamic_cast< Bird * >( amnimal ); if( 0 != bird ) { amnimal->fly(); } }
良い例
class Animal { // 何もしない virtual void fly() { } … } class Bird : public Animal { // 飛ぶ処理 void fly() { … } }
こうすれば、分岐がいらなくなる。
// 飛ぶイベント発生 void event( Animal * amnimal ) { // 鳥なら飛ぶ amnimal->fly(); }
- それだと余りに冗長だったり、基底クラスがライブラリとかで弄れない場合にcastを使うべし
そんな感じ