現在C++にてシューティングゲームを作っているのですが、良く分からないことがあり質問しました。
現状を説明しますと
敵単体の基本クラスであるEnemyDataクラスがあり、そこにはmove()関数いうその敵の行動を制御する関数があり、これは
virtual void move(){}と基本クラスでは何もしません。
そして、その派生クラスEnemy1にてこの関数をオーバーライドして、そこでmove()関数の中身を書き実際に行動させるとします。
ここで敵全体を制御するEnemyControlクラスがあり、そこにはEnemyDataクラスのリストであるlist<EnemyData> enemy_listがあります。
ここで基本クラスのリストには派生クラスも要素として入れることができるので、
Enemy1 new_enemy;
enemy_list.push_back(new_enemy);
とすれば、enemy_listにてEnemy1も扱うことが出来ると思いました。
しかし、実際にイテレーターをlist<EnemyData>::iterator enemy;と宣言し
enemy=enemy_list.begin();
enemy->move();
とした場合、要素として入れたはずのEnemy1のmove()ではなく、基本クラスのEnemyDataのmove();関数が実行されてしまいました。
これは一体何がいけないのでしょうか?
Enemy1クラスのmove();を実行するにはどのようにすればいいのでしょうか?
回答お願いします。
C++ 連結リストと派生クラスについて
Re: C++ 連結リストと派生クラスについて
ちなみにこれがリストではなく配列の場合
EnemyData* array[100];
Enemy1 enemy1;
array[0]=&enemy1;
array[0]->move();
みたいにすれば、Enemy1クラスのmove()が実行されると思います。
つまりこれと同じことをリストでも行いたいのですが、それをどのようにすればいいのか分からないといった感じです。
EnemyData* array[100];
Enemy1 enemy1;
array[0]=&enemy1;
array[0]->move();
みたいにすれば、Enemy1クラスのmove()が実行されると思います。
つまりこれと同じことをリストでも行いたいのですが、それをどのようにすればいいのか分からないといった感じです。
Re: C++ 連結リストと派生クラスについて
これは、「EnemyData*」の配列ですよね。
同じように、「EnemyData*」のリストとしなければいけません。
したがって、
とし、
もしくは、
のようになります。
ポインタによるポリモーフィズムを使うときの注意点としては、
派生クラスへのポインタを基底クラスへのポインタを通してdeleteする場合は、
基底クラスのデストラクタはvirtualである必要があります。
同じように、「EnemyData*」のリストとしなければいけません。
したがって、
とし、
もしくは、
enemy_list.push_back(new Enemy1());
(*enemy_list.begin())->move();
// new したものは delete
delete *enemy_list.begin();
ポインタによるポリモーフィズムを使うときの注意点としては、
派生クラスへのポインタを基底クラスへのポインタを通してdeleteする場合は、
基底クラスのデストラクタはvirtualである必要があります。
Re: C++ 連結リストと派生クラスについて
>>a5uaさん
回答ありがとうございます!
後者のnewを使ったやり方で記述することで、おかげで無事実行することができました!
助かりました。本当にありがとうございます;;
ちなみに、もしよろしければさらに質問なのですが、
あるリストの要素の削除をイテレーターitを使ってする場合、~~list.erase(it)のようにすることで削除出来ますが、
お教えいただいたnewを使ってリストに要素をpush_back()をした場合、削除するときはやはり
erase()を使わずに、deleteで消さなければならないのでしょうか?
それと前者のやり方の場合、ビルドの際エラーは起きませんでしたが、プログラム実行後、不正アクセス等で中断されたりました。
これはプログラムを見てない以上お答えしかねるとは思いますが、何かしら原因分かりますでしょうか?
回答ありがとうございます!
後者のnewを使ったやり方で記述することで、おかげで無事実行することができました!
助かりました。本当にありがとうございます;;
ちなみに、もしよろしければさらに質問なのですが、
あるリストの要素の削除をイテレーターitを使ってする場合、~~list.erase(it)のようにすることで削除出来ますが、
お教えいただいたnewを使ってリストに要素をpush_back()をした場合、削除するときはやはり
erase()を使わずに、deleteで消さなければならないのでしょうか?
それと前者のやり方の場合、ビルドの際エラーは起きませんでしたが、プログラム実行後、不正アクセス等で中断されたりました。
これはプログラムを見てない以上お答えしかねるとは思いますが、何かしら原因分かりますでしょうか?
Re: C++ 連結リストと派生クラスについて
eraseすると、そのイテレータが指すポインタにはアクセスできなくなるわけですから、ペキロゲン さんが書きました: あるリストの要素の削除をイテレーターitを使ってする場合、~~list.erase(it)のようにすることで削除出来ますが、
お教えいただいたnewを使ってリストに要素をpush_back()をした場合、削除するときはやはり
erase()を使わずに、deleteで消さなければならないのでしょうか?
ポインタをdeleteをした後に、その要素をeraseする必要があります。
list<EnemyData *> enemy_list;
void MoveEnemies()
{
list<EnemyData *>::iterator it = enemy_list.begin();
while (it != enemy_list.end()) {
(*it)->move();
if ((*it)->is_dead()) {
delete *it;
it = enemy_list.erase(it);
} else {
++it;
}
}
}
もし、以下のコードにおけるAddNewEnemy1のような使い方をしている場合、ペキロゲン さんが書きました: それと前者のやり方の場合、ビルドの際エラーは起きませんでしたが、プログラム実行後、不正アクセス等で中断されたりました。
これはプログラムを見てない以上お答えしかねるとは思いますが、何かしら原因分かりますでしょうか?
ローカル変数の寿命により、アクセスできなくなることは考えられます。
list<EnemyData *> enemy_list;
void AddNewEnemy1()
{
Enemy1 new_enemy;
enemy_list.push_back(&new_enemy);
//new_enemyが破棄されるため、リスト内のEnemyDataにアクセスできる保証は全くなくなる
}
void AddNewEnemy2()
{
enemy_list.push_back(new Enemy1());
// newしたオブジェクトは明示的にdeleteするまで存在する
}
void MoveEnemies()
{
if (some_condition) {
AddNewEnemy1();
AddNewEnemy2();
}
for (list<EnemyData *>::iterator it = enemy_list.begin(); it != enemy_list.end(); ++it) {
(*it)->move();
}
}
スマートポインタをリストの要素にすると、明示的なdeleteは不要になりますが、
詳細はここでは記しませんので、興味があったら調べてみてください。
Re: C++ 連結リストと派生クラスについて
なるほど。非常に分かりやすい回答ありがとうございます!
二つとも調度私がやりたかったこと・やっていたことで、
おかげ様で良く分からなかった二つの疑問点も一気にスッキリしました。
何度もお答えいただき本当に助かりました。ありがとうございました!
最後のスマートポインタに関しては自分で調べてみますね^^;
二つとも調度私がやりたかったこと・やっていたことで、
おかげ様で良く分からなかった二つの疑問点も一気にスッキリしました。
何度もお答えいただき本当に助かりました。ありがとうございました!
最後のスマートポインタに関しては自分で調べてみますね^^;