C++将类指针存储在可以从派生类访问的抽象基类中

C++ Storing a class pointer in an abstract base class that can be accessed from derived classes?

本文关键字:访问 派生 基类 抽象 指针 存储 C++      更新时间:2023-10-16

我想在我的抽象实体类中存储一个指向主Game类的指针。

实体.h

#include "Game.h"
class Entity
{
public:
    Entity(Game* game);
    ~Entity(void);
    virtual void Draw(float dt) = 0;
    virtual void Update(float dt) = 0;          // '= 0' means pure virtual function (like 'abstract' in C#)
protected:
    Game* m_game;                               // Missing type specifier error C4430
};

实体.cpp

#include "Entity.h"
Entity::Entity(Game* game)
{
    m_game = game;
}
Entity::~Entity(void)
{
}

然后,我应该能够实例化一个派生类,并将Game类引用传递到构造函数中,以便将其传递到存储它的基类:

Boundary.h

#include "Entity.h"
class Boundary : public Entity
{
public:
    Boundary(Game* game);
    ~Boundary(void);
    // Override pure virtual functions
    void Draw(float dt);
    void Update(float dt);
};

Boundary构造函数可以使用引用的Game类将自己添加到列表中:

#include "Boundary.h"
Boundary::Boundary(Game* game) : Entity(game)
{
    // Add entity to the main entity list
    game->m_entities->push_back(*this);
}
Boundary::~Boundary(void)
{
}
void Boundary::Draw(float dt)
{
    // Call the base class as follows (C# equivalent: 'base.Draw(dt)')
    //Entity::Draw(dt);
}
void Boundary::Update(float dt)
{
}

这会导致3种问题:

game->m_entities->push_back(*this);

错误C2663:"std::list&lt_Ty,_Ax>::push_back':2个重载对"this"指针没有合法转换

实体.h 中的Game* m_game;

错误C4430:缺少类型说明符-假定为int

Game.h 中的list<Entity>* m_entities;

错误C2065:"实体":未声明的标识符

实体.h 中的Entity(Game* game);

错误C2061:语法错误:标识符"游戏"

我试图实现的C#等价物是:

public abstract class Entity
{
    protected Game game;
    public abstract void Draw(float dt);
    public abstract void Update(float dt);
}
public class Boundary : Entity
{
    public Boundary(Game game)
    {
        this.game = game;
        game.Entities.Add(this);
    }
    public override void Draw(float dt)
    {
    }
    public override void Update(float dt)
    {
    }
}

我哪里错了?

编辑:

Game.h
#include "btBulletDynamicsCommon.h"
//#include "LinearMathbtQuaternion.h"
#include <list>
using namespace std;        // Required for list
class Entity;               // Forward declaration
class Game
{
public:
    list<Entity>* m_entities;
    Game(void);
    ~Game(void);
    void init();
    void draw(float dt);
    void loadContent();
    void update(float dt);
private:
    class btDefaultCollisionConfiguration* m_collisionConfiguration;
    class btCollisionDispatcher* m_dispatcher;
    class btDiscreteDynamicsWorld* m_dynamicsWorld;
    class btBroadphaseInterface* m_overlappingPairCache;
    class btSequentialImpulseConstraintSolver* m_solver;
    void exitPhysics();
    void initPhysics();
};

编辑2:

我现在唯一剩下的问题是试图在构造函数中引用游戏:

    Boundary::Boundary(Game *game) 
    : Entity(game)                  // Initialise base
{
    // Add entity to the main entity list
    game->m_entities->push_back(*this);      // ERROR
}

基类也有同样的问题

    Entity::Entity(Game* game) 
    : m_game(game)                  // Initialise members
{
    m_game->m_entities->push_back(this);     // ERROR here too
}

后期编辑

游戏中的这一行。h:

list<Entity>* m_entities;

声明一个指向实体实例列表的指针。除了在您看到实体的定义之前不能使用此列表之外(这在这里不是问题),这也意味着您放入列表中的任何实体都将被复制。由于您使用的是Entity的子类,这将对对象进行切片,并且只复制基类部分。因此,您的列表是而不是多态的。而且,每次创建Boundary(或其他)时,它都会尝试将其Entity基类子对象的副本添加到列表中。

考虑一下:

list<Entity*> m_entities;

并且可能也将push_back移动到基类:

Entity::Entity(Game *game) : m_game(game)
{
    game->m_entities.push_back(this);
}
Boundary::Boundary(Game *game) : Entity(game) {}

(所以你不必为每个子类复制它)。

通常,当您想要运行时多态性(派生类和虚拟函数)时,您需要使用间接性

std::list<std::unique_ptr<Entity> > m_entities;

哦,如果您通过基类间接删除派生类型(就像这里一样),那么基类析构函数也应该声明为虚拟的。


预编辑

缺少类型说明符错误是您的第一条线索:当您在Entity的定义中引用Game时,编译器无法弄清楚它是什么。

由于包含了Game.h,所以该标头可能有问题,或者存在循环依赖关系(即Game.h也包含Entity.h)。

但是,您根本不需要在其中包含Game.h

实体.h

#ifndef USER1423893_ENTITY_H
#define USER1423893_ENTITY_H
class Game; // forward declaration
class Entity
{
public:
    virtual ~Entity(void);
    virtual void Draw(float dt) = 0;
    virtual void Update(float dt) = 0;
protected:
    explicit Entity(Game* game);
    Game* m_game;
};
#endif

实体.cpp

#include "Entity.h"
Entity::Entity(Game* game) : m_game(game)
{
}

既然你已经修复了这个错误,会发生什么?