在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.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(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 Headers 更改为以下内容
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_game
不是将Game类的实例分配给堆栈吗?如果要表示引用,应如何在 Headers 中声明?
编辑2
如果我在基础实体类 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);
};
例如,我在尝试访问派生的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&
为什么是这样?
2 回答
永远不应从任何
Entity
或派生类中删除Game
对象 . 它应该是应用程序关闭之前要解除分配的最后一件事 .您应该将其作为
Game&
传递给Entity
类 . 为什么?因为你只有一个Game
的实例,所以不需要重置它指向的内容,它总是应该有效(因为游戏将在Entity
对象之前存在) .另一种选择是在
Game
类中实现 Singleton Pattern ,并像这样访问Game::GetInstance().m_dynamicsWorld->removeRigidBody(m_body);
根据您的编辑,您可以使用初始化列表创建
Entity
. 这样你可以存储const成员,如下所示:你的设计有缺陷 . 您需要明确说明(通过您的设计)谁拥有指针 . 如果
Entity
拥有指针,那么它应该在你的析构函数中释放它(更好的是;只需将它包装在_434116中) . 如果它不拥有指针,那么就不要解除分配 .你不可能两种方式 . 你正在使用
shared_ptr
,这意味着多个"owners",并且一旦完成最后一个所有者,内存将被释放 . 同样,你需要清楚地设计谁拥有这个记忆 .从您的代码来看,似乎
Entity
并不真正拥有Game*
. 它出于实现原因需要它,但不应对其解除分配负责 .在旁注中,您违反了The Rule of Three .