C++はJavaと違って様々なキャスト演算子がある.標準のキャストが以下の4つである.
- Static cast
- Dynamic cast
- Const cast
- Reinterpret cast
勿論Cスタイルのキャスト - Javaでおなじみの, カッコでくくるキャスト演算子 - もある.C言語スタイルのキャストはstatic, const, reinterpretのいずれかのキャストと同じことをするのだが,C++では使うべきではない.(こちらを参照されたし)
C++のキャストは注意深く,丁寧にC言語のキャストを機能毎に3つに分割し,かつ新たにdynamic_castを追加しているのである.4つのキャストの内,static_castは最も直観的なキャストであり,longからint, intからcharといったような型変換 かつ 変数の中身の変換を行ってくれる.
Dynamic_castはダウンキャストを行う時に,継承関係の検査を行い,正しくないキャストの場合はポインタの場合はNULL,参照の場合はstd::bad_cast例外をスローする.Reinterpret castは型だけを変換し,内部の値はタッチしない.(こちらを参照されたし).最後のconst_castはvolatileとconstを打ち消してくれるキャストである.
私のやっていることは正しいか?
Static_castはまあいいとして,他の3つのキャストを使う場面に出くわしたときは必ず以下のことを自問してほしい.
私のやっていることは,正しいのか?
このデザインは,なんか間違ってるんじゃないのか?
本当に,仕方がないのか?
これをやったら,それなりのベネフィットは,あるのか?
以上の自問について,あなたが自分と(可能ならばpeer)を納得できる答えを返すことができれば,実に結構.さもなれければリファクタリングに取り掛かったほうがよいのかもしれない.
サンプル
以下の例はstatic_cast, const_castそしてdynamic_castを使った例である.サンプルコードという手前もあって極めてナンセンスなコードであるが,上記キャストの用例としては適当かと思う.ちなみにこのコードを目の前にして上述の自問をすれば全ての問いに対して答えは,big noである.
#include <cstdio> #include <string> using namespace std; class Base { protected: int fieldA; public: Base() { fieldA = 0;}; virtual void ShowField(const string* prefix ) { printf("%s-%d\n", prefix->c_str(), fieldA); } }; class Child: public Base { public: Child(); void ShowField(const string* prefix); }; Child::Child(): Base() { printf("Child created.\n"); } void Child::ShowField(const string* prefix) { Base::ShowField( prefix ); string* p = const_cast<string*>(prefix); *p = "--the jail breaker--"; } class Stranger { public: Stranger() {} }; int main() { // static_cast double d = 50.0; printf( "staticcast - %d\n", static_cast<int>(d) ); // const_cast Child c; string str = "abc"; c.ShowField(&str); printf("%s\n",str.c_str()); // dynamic_cast Stranger *pS = dynamic_cast<Stranger*>(&c); if( pS == NULL ) printf("downcast failed as per the pS content"); return 0; }
実行結果
staticcast - 50 Child created. abc-0 --the jail breaker-- downcast failed as per the pS content
0 件のコメント:
コメントを投稿