2010年5月9日日曜日

コンストラクタで仮想関数を呼び出す(C++)

C++ではコンストラクタで仮想関数を呼び出しても意図した動作にならないんですよね、どんな動きになるかといいますと、オーバーライドした関数ではなく基底クラス(親クラス)の仮想関数が呼び出されてしまいます。
検証用のコードを用意しましたのでまずはクラス図を見てみましょう。

単純な継承関係のクラスを二つ用意しました。init()は仮想関数になっています。
つぎにソースを見てみましょう、用意したのは次のファイルです。
  • main.cpp
  • Character.h
  • CharacterMonster.h
まずはCharacter.hです。
  1. #ifndef _CHARACTER_H_  
  2. #define _CHARACTER_H_  
  3.   
  4. #include <stdio.h>  
  5. class Character  
  6. {  
  7. public:  
  8.     // constructor  
  9.     Character() {  
  10.         this->init();  
  11.     }  
  12.   
  13.     // destructor  
  14.     ~Character() {  
  15.         // do nothing...  
  16.     }  
  17.   
  18. protected:  
  19.     virtual void init() {   //  仮想関数で定義  
  20.         printf("init Character\n");  
  21.     }  
  22. };  
  23. #endif  
  24. </stdio.h>  

次にCharacterMonster.hです。
  1. #ifndef _CHARACTER_MONSTER_H_  
  2. #define _CHARACTER_MONSTER_H_  
  3.   
  4. #include "Character.h"  
  5.   
  6. class CharacterMonster : public Character  
  7. {  
  8. public:  
  9.  // constructor  
  10.  CharacterMonster() {  
  11.   // do nothing...  
  12.  }  
  13.   
  14.  // destructor  
  15.  virtual ~CharacterMonster() {  
  16.   // do nothing...  
  17.  }  
  18.   
  19. protected:  
  20.  virtual void init() { // オーバーライド  
  21.   printf("init Character Monster\n");  
  22.  }  
  23. };  
  24. #endif  

最後にmain.cppです。
  1. #include "CharacterMonster.h"  
  2. #include <stdio.h>  
  3.   
  4. void main(void)  
  5. {  
  6.     Character* character = new CharacterMonster();  
  7.     delete character;  
  8.   
  9.     printf("hit any key...");  
  10.     while(getchar() == EOF){}  
  11. }  
  12. </stdio.h>  
init()はオーバーライドされているのでこのプログラムを実行すると「init Character Monster」が表示されると思いきや「init Character」が表示されてしまいます。
ということでコンストラクタで仮想関数を呼び出しても意図した動作になりませんでした。
ちなみにinit()を純粋仮想関数にした場合は実体がないためリンクエラーとなります。

なのでinit()メソッドをいつも用意するようにしているのですけどinit()を呼び出すのを忘れたりもするんですよね、ケースバイケースなのかなぁ?。

0 件のコメント:

コメントを投稿