在Game类函数中,我将一个Boundary类分配给堆栈
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::~DynamicEntity(void)
{
m_game->m_dynamicsWorld->removeRigidBody(m_body);
delete m_body;
}
DynamicEntity派生自名为Entity
的所有游戏对象的基类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(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&amp; amp;的建议游戏
看来我必须将我的Entity标题更改为以下
#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类的实例分配给堆栈吗?如果要表示引用,应如何在标题中声明?
如果我在基础实体类const Game &m_game
中存储对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);
};
例如,在尝试访问派生边界类源的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&amp;
为什么会这样?
答案 0 :(得分:2)
您的设计存在缺陷。您需要清楚地说明(通过您的设计)谁拥有指针。如果Entity
拥有指针,那么它应该像你一样在它的析构函数中释放它(更好的是,只需将它包装在std::unique_ptr
中)。如果它没有指针,那么就不要解除分配。
你无法双管齐下。您正在使用shared_ptr
,因此这意味着多个“所有者”,并且一旦完成最后一个所有者,内存将被取消分配。同样,你需要清楚地设计谁拥有这个记忆。
从您的代码判断,似乎Entity
并不真正拥有Game*
。它出于实现原因需要它,但不应对其解除分配负责。
在旁注上,您违反了The Rule of Three。
答案 1 :(得分:2)
永远不应从任何Game
或派生类中删除Entity
对象。它应该是应用程序关闭之前要解除分配的最后一件事。
您应该将其作为Entity
传递给Game&
个班级。为什么?因为你只有Game
的一个实例,所以不需要重置它所指向的内容,而总是应该是有效的(因为游戏将存在于{{1}之前对象do)。
另一个选择是在Entity
课程中实施单身人士模式,并像Game
根据您的修改,您可以使用初始化列表创建Game::GetInstance().m_dynamicsWorld->removeRigidBody(m_body);
。这样就可以存储const成员,如下所示:
Entity