user1423893
user1423893

Reputation: 796

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

I would like to store a pointer to the main Game class in my abstract Entity class.

Entity.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
};

Entity.cpp

#include "Entity.h"

Entity::Entity(Game* game)
{
    m_game = game;
}

Entity::~Entity(void)
{

}

I should then be able to instantiate a derived class and pass the Game class reference into the constructor so that it is passed to the base class where it is stored:

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);
};

The Boundary constructor can then use the referenced Game class in order to add itself to a list:

#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)
{

}

This causes 3 kinds of problems:

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

error C2663: 'std::list<_Ty,_Ax>::push_back' : 2 overloads have no legal conversion for 'this' pointer

Game* m_game; in Entity.h

error C4430: missing type specifier - int assumed

list<Entity>* m_entities; in Game.h

error C2065: 'Entity' : undeclared identifier

Entity(Game* game); in Entity.h

error C2061: syntax error : identifier 'Game'

The C# equivalent of what I am trying to achieve is:

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)
    {

    }
}

Where have I gone wrong?

EDIT:

Game.h

#include "btBulletDynamicsCommon.h"
//#include "LinearMath\btQuaternion.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();
};

EDIT 2:

The only problem I am left with now is trying to refer to game in the constructor:

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

The base class suffers from the same problem

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

Upvotes: 1

Views: 1606

Answers (1)

Useless
Useless

Reputation: 67733

post-edit

This line in Game.h:

list<Entity>* m_entities;

declares a pointer to a list of Entity instances. Apart from the fact that you can't use this list until you've seen the definition of Entity (which isn't a problem here), it also means that any Entity you put into the list will be copied. Since you're using subclasses of Entity, this will slice the object and only copy the base-class part. So, your list is not polymorphic. And, every time you create a Boundary (or whatever), it tries to add a copy of only its Entity base class subobject to the list.

Consider this instead:

list<Entity*> m_entities;

and maybe move the push_back to the base class too:

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

Boundary::Boundary(Game *game) : Entity(game) {}

(so you don't have to copy that for every subclass).

In general, when you want runtime polymorphism (derived classes and virtual functions) you need to use indirection such as pointers or references. Now that you're storing pointers, it's also a good idea to think about ownership and lifetime (storing smart pointers rather than raw pointers in that entity list might be a good start).

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

Oh, and if you're deleting derived types via a base class indirection (like here), the base class destructor should be declared virtual as well.


pre-edit

The missing type specifier error is your first clue: the compiler can't figure out what Game is when you refer to it in the definition of Entity.

Since you're including Game.h, either there's a problem with that header, or a circular dependency (ie, Game.h also includes Entity.h).

However, you don't need to include Game.h there at all:

Entity.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

Entity.cpp

#include "Entity.h"

Entity::Entity(Game* game) : m_game(game)
{
}

What happens now you've fixed that error?

Upvotes: 3

Related Questions