1

So it is my understanding that to make a class abstract in c++ you have to create one, just one, pure virtual method in that class. In my code i create an abstract GameObject class, which is inherited by my Player class, but the problem is i get errors in my Player.cpp saying error LNK2001: unresolved extrenal symbol "public:virtual void__thiscall GameObject::Load(void)" (?Load@GameObject@@UAEXXZ) for every method except the initialise, and this gets fixed when i set them all = 0, im just wondering why

// Abstract class to provide derived classes with common attributes

#include <SDL.h>
#include "AnimationManager.h"
#include "Debug.h"
#include "InputHandler.h"

class GameObject
{
public:
    virtual void Initialise() = 0;
    virtual void Load();
    virtual void HandleEvents();
    virtual void Update();
    virtual void Draw();
    Vector2D* position;
    int currantFrame;
    SDL_Renderer* renderer;
    float speed;
    bool alive;
};



#include "GameObject.h"

class Player : public GameObject
{
public:
    virtual void Initialise();
    virtual void Load();
    virtual void HandleEvents();
    virtual void Update();
    virtual void Draw();
    Player(SDL_Renderer* r);
    ~Player();
};



#include "Player.h"

Player::Player(SDL_Renderer* r)
{
    renderer = r;
}

Player::~Player()
{
}

void Player::Initialise()
{
    position = new Vector2D(10, 10);
    currantFrame = 0;
}

void Player::Load()
{
    TheAnimationManager::Instance()->load("Assets/circle.png", "player", renderer);
}

void Player::HandleEvents()
{
    SDL_Event event;

    if (SDL_PollEvent(&event))
    {
        switch(event.type)
        {
            case SDL_KEYDOWN:

                switch(event.key.keysym.sym)
                {
                    case SDLK_a:
                        DEBUG_MSG("A Pressed");
                        position->m_x -= 10;
                    break;

                    case SDLK_d:
                        DEBUG_MSG("D Pressed");
                        position->m_x += 10;
                    break;
                }

            break;
        }
    }
}

void Player::Update()
{
    Vector2D* p = TheInputHandler::Instance()->GetMousePosition();
    DEBUG_MSG(p->GetY());
    DEBUG_MSG(p->GetX());

    currantFrame = int(((SDL_GetTicks() / 100) % 4));
}

void Player::Draw()
{
    TheAnimationManager::Instance()->Animate("player", (int)position->GetX(), (int)position->GetY(), 90, 82, 0, currantFrame, renderer, SDL_FLIP_NONE);
}
Oblivion
  • 585
  • 2
  • 8
  • 26
  • 3
    What errors do you get? – David Brown Nov 15 '13 at 23:58
  • 1) Please post the exact error, and the corresponding line. 2) Please make sure that *each* abstract method in your abstract class has a corresponding implementation in your "Player" class (it looks like you're already doing this). 3) Here's a good link: [Abstract base class example](http://publib.boulder.ibm.com/infocenter/comphelp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8a.doc%2Flanguage%2Fref%2Fcplr142.htm) – paulsm4 Nov 16 '13 at 00:04
  • edited my question and code – Oblivion Nov 16 '13 at 00:22

4 Answers4

5

Every virtual method which might be called through a base class pointer that isn't pure virtual needs to have an implementation.

You seem to have a backwards idea of how abstract/virtual works. You don't choose to make a class abstract, why would you? You choose to make a member function pure virtual, because there is no sensible implementation for it. Then, as a consequence of having a pure virtual function, the class becomes abstract.

The class becoming abstract does not mean that every one of its functions suddenly becomes pure virtual.

Your error is a linker error. The linker was looking for the implementation of the GameObject::Load function, which you didn't provide. If you mark the function as pure virtual, the linker won't look for an implementation.

Benjamin Lindley
  • 101,917
  • 9
  • 204
  • 274
  • 2
    Not quite. A non-`virtual` method only needs to be defined if it can be called somehow. – Dietmar Kühl Nov 16 '13 at 00:03
  • for example, if i take away the = 0 part of the initialise method in the GameObject class, i get this error error LNK2001: unresolved extrenal symbol "public:virtual void__thiscall GameObject::Initialise(void)" (?Initialise@GameObject@@UAEXXZ) – Oblivion Nov 16 '13 at 00:04
  • The reason i choose to make it abstract is because GameObject must never be instantiated, so i make it abstract to make sure it never gets instantiated – Oblivion Nov 16 '13 at 00:06
  • @DietmarKühl: Good point. Better? Henrique, I edited it, and even that was wrong. – Benjamin Lindley Nov 16 '13 at 00:07
  • The "which is called through a base class pointer" part is wrong. It's sufficient that it *might* be, in some other compilation unit, which is *really* hard to disprove. So pretty much, all virtual methods must either have an implementation or be declared pure (non-exclusive OR, that). – Ben Voigt Nov 16 '13 at 00:09
  • Standard says: "A virtual member function is odr-used if it is not pure." So it has to be defined even if it provably cannot be called. – Ben Voigt Nov 16 '13 at 00:12
  • @BenjaminLindley: what Ben Voigt said: if a function is `virtual` and not pure, it has to be defined. If it is pure, it can be defined (sorry, couldn't resist messing with that...). Whether it is actually ever called is immaterial. – Dietmar Kühl Nov 16 '13 at 00:21
  • 2
    @Jake: That's the implementation for `Player`. `GameObject` needs one, unless you mark it pure virtual. – Benjamin Lindley Nov 16 '13 at 00:25
  • ah ok i get ya, the fact i dont have a GameObject.cpp file is my problem, as none of GameObjects methods are being implemented, just inherited and then implemented, but i dont want to have one of those cpp files so i get away with not having one by putting them all as pure virtual – Oblivion Nov 16 '13 at 00:33
0

Some compilers require that for each signature the virtual keyword would specified only once, in the base class. Try this:

class GameObject
{
public:
    virtual void Initialise() = 0;
    virtual void Load() = 0;
    virtual void HandleEvents() = 0;
    virtual void Update() = 0;
    virtual void Draw() = 0;
...
};

class Player : public GameObject
{
public:
    void Initialise();
    void Load();
    void HandleEvents();
    void Update();
    void Draw();
...
};
Michael
  • 5,775
  • 2
  • 34
  • 53
  • Those would not be C++ compilers. – Ben Voigt Nov 16 '13 at 00:13
  • @BenVoigt: It used to be like that in early VC++, circa 2000. According to [this](http://stackoverflow.com/questions/4895294/c-virtual-keyword-for-functions-in-derived-classes-is-it-necessary) and other sources virtual keyword in derived classes should be optional but harmless in modern standards-compliant compilers. – Michael Nov 16 '13 at 00:22
0

if you don't need the public GameObject::Initialise method be pure virtual, at least give it an empty body, like this

class GameObject
{
public:
    void Initialise() {}
    ...
};
leixure
  • 41
  • 1
0

Another conjecture: do you have, by any chance, any instantiations of GameObject in your code? Do you have something like this:

GameObject go;

or something like this:

void foo( GameObject go );

or something like this:

GameObject bar();

or something like this:

vector<GameObject> all_my_objects;
Michael
  • 5,775
  • 2
  • 34
  • 53