1

在 Game 类函数中,我将 Boundary 类分配给堆栈

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

边界类有一个指向主游戏类的指针和一个指向刚体的指针。我不确定是否应该为每个使用参考?由于稍后解释的原因,这里的一些清晰度会有所帮助。

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 的游戏对象的基类

实体.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*,并且在尝试调用任何虚拟方法时会发生错误。

我希望边界指针一直存在,直到我说删除。有没有办法在不将边界分配给堆的情况下做到这一点?

编辑

回应使用const& Game的建议

看来我必须将我的实体标头更改为以下

实体.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_game将 Game 类的实例分配给堆栈吗?如果它代表一个引用,它应该如何在标题中声明?

编辑 2

如果我在基实体类中存储对 Game 类的受保护引用,const Game &m_game我似乎无法访问g_wireShapeDrawer派生类中 Game 类的全局成员。

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

你的设计有缺陷。您需要清楚地说明(通过您的设计)谁拥有指针。如果Entity拥有该指针,那么它应该像您所做的那样在其析构函数中释放它(更好;只需将其包装在 a 中std::unique_ptr)。如果它不拥有指针,那么就不要释放它。

你不能同时拥有它。您正在使用 a shared_ptr,因此这意味着多个“所有者”,并且一旦最后一个所有者完成了它,内存将被释放。同样,您需要围绕谁拥有此内存进行明确设计。

从您的代码来看,似乎Entity并不真正拥有Game*. 它出于实现原因需要它,但不应对其释放负责。


在旁注中,您违反了三法则

于 2012-09-19T21:20:21.357 回答
2

Game永远不要从任何Entity类或派生类中删除该对象。在应用程序关闭之前,它应该是最后被释放的东西之一。

您应该将其Entity作为Game&. 为什么?因为你只有一个 的实例Game,所以不需要重置它指向的东西,它应该总是有效的(因为游戏将在Entity对象之前存在)。

另一种选择是在你的类中实现单例模式Game,并像这样访问它Game::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 回答