河原林研究室>>ワンマン的日記>>compiling trouble
このページでは、以下のような問題に対して、言及する。
コンパイルができない(コンパイルエラー) |
コンパイルは通ったが、実行時エラーが出る |
コンパイルは通ったが、思い通りに動かない |
よく起こること
int a[10]; a[10] = 23; // NG
Object obj = NULL; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ obj.print(); // NG
Object *o = getObjectPointer(); o->print(); // NG ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Object* getObjectPointer() { Object obj( "local object" ); return &obj; }
メンバ関数へポインタを用いて関数を呼び出そうとしたが、コンパイルで下記のエラーが出る。
typedef string (Object::*F)(string)
F f = &Object::func; string result = (this->*f)( "aaa" ); //OK //string result = this->*f( "aaa" ); //NG
this->*f( "aaa" )のほうでは、解釈が曖昧になりコンパイルを通らない。
informative discussion : http://www.gamedev.net/community/forums/topic.asp?topic_id=528416
cf.共通の親クラスをもつ派生クラスのポインタを配列で管理する。
Object | 親クラス |
SubObject1 | 派生クラス |
SubObject2 | 派生クラス |
Object *obj[3]; obj[0] = new Object(); obj[1] = new SubObject1(); obj[2] = new SubObject2(); for( int i=0; i<3; i++ ) { obj[i]->print(); }
この例では、それぞれのクラスで定義されたprintが呼び出される。
一方、
cf.共通の親クラスをもつ派生クラスの実体を配列で管理(しようと)する。
Object obj[3]; Object o1; SubObject1 o2; SubObject2 o3; obj[0] = o1; obj[1] = o2; obj[2] = o3; for( int i=0; i<3; i++ ) { obj[i].print(); }
この例では、すべてObjectクラスのprintが呼び出される。
[solution]
どうしても、実体で管理したいのだーという場合。
class SomeObject { private: Object *obj; public: template <class X> void setObj( X* a ) { /* オブジェクトのポインタを受け取りコピー処理を行うコンストラクタ(X(a)) を用いて生成されたオブジェクト(X)のポインタをobjが受け取る。 */ obj = new X( a ); // コピーコンストラクタではない。 } void print() { obj->print(); } }; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SomeObject obj[3]; Object o1; SubObject1 o2; SubObject2 o3; obj[0].setObj( &o1 ); obj[1].setObj( &o2 ); obj[2].setObj( &o3 ); for( int i=0; i<3; i++ ) { obj[i].print(); }
(何か他にいい方法もあるんかもしれんけど、)知らぬ間に実体が死んでいることを防ぐために
実体としてデータが同じものをコピーしてしまうソリューション。~