1

Game クラス関数で、境界クラスをスタックに割り当てています

void Game::loadContent()
{
    Boundary b(this, body); 
}

境界クラスには、メインの Game クラスへのポインターと剛体へのポインターがあります。ただし、それぞれに参照を使用する必要があるかどうかはわかりませんか? ここで明確にすることは、後で説明する理由のために役立ちます。

class Boundary : public DynamicEntity
{
public:
    Boundary(Game *game, btRigidBody *body);
    ~Boundary(void);

    // Override functions
    virtual void draw(float dt);
    virtual glm::vec3 getPosition();
    virtual void update(float dt);
};

DynamicEntity クラスは本体を割り当て、デストラクタでポインタの削除を処理します。

class DynamicEntity : public Entity
{
public:
    virtual ~DynamicEntity(void);

    virtual void draw(float dt) = 0;
    btRigidBody* getBody();
    glm::vec3 getPosition() = 0;
    virtual void update(float dt) = 0;

protected:
    explicit DynamicEntity(Game *game, btRigidBody *body);
    btRigidBody *m_body;
};

DynamicEntity.cpp デストラクタ

DynamicEntity::~DynamicEntity(void)
{
    m_game->m_dynamicsWorld->removeRigidBody(m_body);

    delete m_body;
}

DynamicEntity は、Entity と呼ばれるすべてのゲーム オブジェクトの基本クラスから派生します。

Entity.h

class Entity
{
public:
    // Make destructor virtual as this is a base class
    virtual ~Entity(void);

    virtual void draw(float dt) = 0;
    int getID();                                
    virtual glm::vec3 getPosition() = 0;
    virtual void update(float dt) = 0;          

protected:
    explicit Entity(Game *game);                // Abstract base constructor

    Game *m_game;
    int m_id;                                   // Unique ID
};

このクラスのデストラクタで Game クラス ポインタに対して delete を呼び出すことはできませんが、ポインタとして渡すことが (参照ではなく) 正しいメソッドであるかどうかわからないのはなぜですか?

Entity::~Entity(void)
{
    // Derived class destructors are called first
    delete m_game;  // ERROR
}

Entity クラスは、それ自体へのポインターを追加します。これは、Game クラスのリストを介してアクセスできます (メインの Game クラスで Entity 関数を反復および呼び出すのに役立ちます)。

Entity::Entity(Game *game) 
    : m_game(game),                                         // Initialise members
    m_id(m_game->g_idGenerator->generateNewID())            // Generate unique ID                       
{
    m_game->m_entities.push_back(std::shared_ptr<Entity>(this));
}

私が抱えている主な問題は、Game::loadContent()メソッドが終了すると、Entity クラスに対してデストラクタが呼び出されることです。これにより、リストに格納されている *shared_ptr* が破棄され、仮想メソッドを呼び出そうとするとエラーが発生します。

削除と言うまで境界ポインタを保持したいと思います。Boundary をヒープに割り当てずにこれを行う方法はありますか?

編集

const& Gameの使用に関する提案に応えて

エンティティヘッダーを次のように変更する必要があるようです

Entity.h

#pragma once

#include <glm\glm\glm.hpp>

#include "Game.h"

// Forward declarations
class Game;

class Entity
{
public:
    // Make destructor virtual as this is a base class
    virtual ~Entity(void);

    // '= 0' means pure virtual function (like 'abstract' in C#)
    // This means they do not have to be declared in the source file '.cpp'
    virtual void draw(float dt) = 0;
    int getID();                                
    virtual glm::vec3 getPosition() = 0;
    virtual void update(float dt) = 0;          

protected:
    explicit Entity(const Game &game);          // Abstract base constructor

    Game m_game;
    int m_id;                                   // Unique ID
};

Game m_gameGame クラスのインスタンスをスタックに割り当てませんか? 参照を表す場合、ヘッダーでどのように宣言する必要がありますか?

編集2

Game クラスへの保護された参照を基本エンティティ クラスに格納すると、派生クラスconst Game &m_gameの Game クラスのグローバル メンバーにアクセスできないようです。g_wireShapeDrawer

class Game
{
public:
    GL_WireShapeDrawer g_wireShapeDrawer;

    Game(void);
    ~Game(void);

    void init();
    void draw(float dt);
    void handleInput(float dt);
    void loadContent();
    void update(float dt);
};

たとえば、派生 Boundary クラス ソースの draw メソッドでグローバル メンバーにアクセスしようとすると、次のエラーが発生します。

void Boundary::draw(float dt)
{
    m_game.g_wireShapeDrawer.drawPlane(glm::vec3(0, 1, 0), 0.0f, glm::vec4(1, 1, 1, 1));
}

エラー C2662: 'GL_WireShapeDrawer::drawPlane': 'this' ポインタを 'const GL_WireShapeDrawer' から 'GL_WireShapeDrawer &

どうしてこれなの?

4

2 に答える 2

2

オブジェクトは、GameどのEntityクラスまたは派生クラスからも決して削除しないでください。アプリケーションがシャットダウンする前に、最後に割り当てを解除する必要があります。

Entityとしてクラスに渡す必要がありますGame&。なんで?のインスタンスは 1 つしかないためGame、それが指すものをリセットする必要はなく、常にEntity有効である必要があります (オブジェクトが存在する前にゲームが存在するため)。

別のオプションは、クラスにシングルトン パターンを実装し、次のようにアクセスすることです。GameGame::GetInstance().m_dynamicsWorld->removeRigidBody(m_body);

Entity編集に従って、初期化子リストを使用して作成できます。このようにして、次のように const メンバーを格納できます。

class Entity
{
  protected:
    explicit Entity(Game &game) : m_game(game) {}
  private:
    Game& m_game;
}
于 2012-09-19T21:43:32.967 に答える
2

あなたのデザインには欠陥があります。誰がポインターを所有しているかを (設計を通じて) 明確に述べる必要があります。Entityがポインタを所有している場合は、あなたが行っているようにデストラクタで割り当てを解除する必要があります(さらに良いのは、 でラップするだけですstd::unique_ptr)。ポインターを所有していない場合は、単に割り当てを解除しないでください。

両方の方法を持つことはできません。を使用しているshared_ptrため、複数の「所有者」を意味し、最後の所有者がそれを処理すると、メモリの割り当てが解除されます。繰り返しになりますが、このメモリの所有者を明確に設計する必要があります。

あなたのコードから判断すると、Entity実際にはGame*. 実装上の理由で必要ですが、割り当て解除について責任を負うべきではありません。


ちなみに、あなたはThe Rule of Threeに違反しています。

于 2012-09-19T21:20:21.357 に答える