第42章 ダウンキャスト

 前回に続いて、今回もC++のキャストについて話します。C言語のキャストにはない特別な機能を持ったキャストです。


 では、今回の要点です。


 では、いってみましょう。


 先ずは、前回の CFile と CBinaryFile と CTextFile の話を思いだしてみましょう。CBinaryFile クラスのオブジェクトのアドレスを一旦 CFile* に渡したものを CTextFile* にキャストすると困るというものでした。(ここで、CBinaryFile と CTextFile は CFile の派生クラスです。これらは第2部の継承の話で作ったあのクラスそのものです。)

 というのも、CBinaryFile ではバイナリ形式でファイルを開いているので、それを使ってテキスト形式で開いていることを前提として処理をしようとしてもおかしくなります。また、ここでは問題になりませんが、派生クラス特有のメンバ変数があると、もう片方にはそのメンバ変数がないので処理がおかしくなります。

 基底クラスから派生クラスへのキャストはダウンキャストと呼びますが、このようにダウンキャストは危険を伴います

 ということで、オブジェクトの真の型とその継承関係をきちんとチェックし、不正なキャストをするとエラーを返すようなキャストがC++では必要になってきます。それが dynamic_cast です。文法は他の3つのキャストと同じです。

CBinaryFile  bin;
CFile*       pFile = dynamic_cast<CFile*>(&bin);
CTextFile*   pText = dynamic_cast<CTextFile*>(pFile);
CBinaryFile* pBin  = dynamic_cast<CBinaryFile*>(pFile);

 上の例では、CBinaryFile* から CFile* へのキャストは特に問題ありませんが、3行目ではさらにそれを CTextFile* でキャストしようとしています。これが上で言っていた困るキャストです。このように困るキャストをすると、dynamic_cast は NULL を返します。戻り値が NULL の時はエラー処理をすればいいわけです。

 4行目では、元が CBinaryFile なので正しいキャストです。この場合は問題なくキャストが行われます。

 このように、dynamic_cast を使えば真のオブジェクトの型とその継承関係をチェックしてくれるわけです。もしここで static_cast を使うと、前回言ったように両方ともそのままキャストされてしまいます。

 dynamic_cast が使えるのは仮想関数を持ったクラスに限ります。このようなクラスをポリモーフィック(多様性を持った)クラスと呼びます。しかし、デストラクタを必ず仮想関数にするので、実質問題この制限はないのと同じ事です。

 dynamic_cast では、void* へキャストすることもできます。しかし、void* からのキャストは行えません

 多重継承というものをすると、もうちょっといろいろな事が起こります。クロスキャストというのにお目にかかることもあるかもしれません。また、アップキャストでも失敗することも出てくるでしょう。しかし、多重継承についてはこの章ではお話ししません。後の章で話すことになるでしょう。


 さて、そうなのかといって dynamic_cast を使ってみようとするとエラーが出てくるかもしれません。少なくともVC++ではそうです。

 実は、dynamic_cast を使うにはランタイムタイプ情報 (RTTI : Run-Time Type Infomation) というものが必要なのです。これがないとコンパイルエラーになります。

 ランタイムタイプ情報を有効にするには、VC++ではプロジェクトの設定をいじる必要があります。プロジェクトの設定はプリコンパイル済みヘッダファイル(第3部第3章参照)でも使いました。Alt+F7 で開くことができます。

 ここの「C++」タブの「C++言語」カテゴリのところに「ランタイムタイプ情報 (RTTI) を有効にする」というのがあると思います。これをチェックして OK ボタンか Enter キーを押せば設定終了です。

 ここで注意することは、ダイアログの左上にある「設定の対象」の横にある指定を「全ての構成」にしておくということです。ビルドの構成が変わったときにランタイムタイプ情報が有効にならず、dynamic_cast のところでエラーが出てしまうからです。

 うっかり忘れてもコンパイルエラーが出たときに設定を直せばいいだけなのですが、慣れないうちは原因が特定しにくいかもしれません。プログラムを作ったばかりのときはいいのですが、完成したと思ったときにこうなると混乱してしまうかもしれません。そういうことのないよう、設定はきちんとしておきましょう。


 最後に。dynamic_cast を使うと処理が遅くなるのではないか、と心配になるかもしれませんが、チェックする必要のないキャスト(普通のアップキャスト)では static_cast と同じ処理に最適化されます。ダウンキャストはそれ程使うことはないので、速度を心配することはないということです。

 ということで、アップキャスト、ダウンキャストには積極的に dynamic_cast を使うといいでしょう。


 では、今回の要点です。


 何か文字ばっかりになってしまいましたね。次回はいつものソースを交えた形式にしたいと思います。


第41章 キャスト | 第43章 心の友よ

Last update was done on 2001.1.12

この講座の著作権はロベールが保有しています