web-dev-qa-db-ja.com

同じ基本クラスの異なる派生クラスへのポインターのベクトル

私はC++で敵のタイプが異なるゲームを書いています。私はベースEnemyクラスを定義し、派生クラスenemy1も持っていますenemy2など。ゲームの各反復でこれらの敵を更新するために、私は配列が欲しい:EnemyArray要素が既存の敵を指しているので、それらのすべてでそれらを確実に更新できますupdate()などの独自バージョン.

これを行う1つの方法は、敵のタイプごとに個別の配列を定義することです。これは問題を解決するためのクリーンな方法です。しかし、これらの敵クラスがすべて同じ基本クラスから派生しているという事実により、私のEnemyArrayをEnemyの後でいくつかの変更を行います。

2
Maths noob

仮想関数Updateを使用して基本クラスと、この関数をオーバーライドする派生クラスを指定できます。これは簡単な例です:

class Enemy
{
public:
    // this is abstract function, but you can also add implementation 
    // as default behavior for derived classes
    virtual void Update() = 0; 
};

class Enemy1 : public Enemy
{
public:
    void Update()
    {
        // update Enemy
    }
}

class Enemy2 : public Enemy
{
    void Update()
    {
        // update Enemy
    }
}

次に、基本クラスへのポインターのベクトルを作成し、特定のタイプのオブジェクトを入力します。

vector<Enemy*> enemies;
enemies.Push_back(new Enemy1());
enemies.Push_back(new Enemy2());

そして、UpdateAll関数は次のようになります。

void UpdateAll()
{
    for (int i = 0; i < enemies.size(); ++i)
    {
        enemies[i]->Update();
    }
}

ポインタを使用しているので、ゲームの最後に割り当てられたすべてのメモリを解放することを忘れないでください。

0
zacharmarz

(私はC++を想定しています)

std::vectorはその要素を値で保持するため、サブクラスを保存する場合はオブジェクトをスライスします。

PImpl idiom を使用してこれを回避できます。具体的な敵への(一意の)ポインターを保持する具体的なEnemyクラスと、カスタムコードを保持する抽象的なIEnemyがあります。

class Enemy
{
  Point location;
  std::unique_ptr<IEnemy> pimpl;

  public:
    Enemy(IEnemy&& pimpl): pimpl(pimpl), location(){}

    void onTick(World w){
        pimpl->onTick(w);
    }
}

あなたは代わりにあなたのベクトルにポインタを保持することができますstd::vector<std::unique_ptr<Enemy>>そのため、値でそれらを保持しません。

0
ratchet freak