【问题标题】:abstract classes C++抽象类 C++
【发布时间】:2013-11-29 12:49:11
【问题描述】:

所以我的理解是,要在 c++ 中创建一个抽象类,您必须在该类中创建一个,只有一个纯虚方法。在我的代码中,我创建了一个抽象 GameObject 类,它由我的 Player 类继承,但问题是我的 Player.cpp 中出现错误,提示错误 LNK2001: unresolved exrenal symbol "public:virtual void__thiscall GameObject::Load(void)" (?Load@GameObject@@UAEXXZ) 除了初始化之外的每个方法,当我将它们全部设置为 0 时,这会得到修复,我只是想知道为什么

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

【问题讨论】:

  • 你得到什么错误?
  • 1) 请发布确切的错误和相应的行。 2) 请确保您的抽象类中的 each 抽象方法在您的“播放器”类中具有相应的实现(看起来您已经在这样做了)。 3)这是一个很好的链接:Abstract base class example
  • 编辑了我的问题和代码

标签: c++ sdl virtual abstract


【解决方案1】:

每个可能通过非纯虚拟基类指针调用的虚拟方法都需要有一个实现。

您似乎对抽象/虚拟的工作方式有一个倒退的想法。您不选择将类抽象化,为什么?您选择将成员函数设为纯虚拟,因为它没有合理的实现。然后,由于具有纯虚函数,该类变得抽象。

类变得抽象并不意味着它的每一个功能都突然变成纯虚拟的。

您的错误是链接器错误。链接器正在寻找您没有提供的 GameObject::Load 函数的实现。如果将函数标记为纯虚拟函数,则链接器不会寻找实现。

【讨论】:

  • 不完全。非virtual 方法仅在可以以某种方式调用时才需要定义。
  • 例如,如果我去掉 GameObject 类中初始化方法的 = 0 部分,我会得到这个错误错误 LNK2001: unresolved exrenal symbol "public:virtual void__thiscall GameObject::Initialise(void) " (?Initialise@GameObject@@UAEXXZ)
  • 我选择抽象的原因是因为GameObject永远不能被实例化,所以我把它抽象化以确保它永远不会被实例化
  • @DietmarKühl:好点子。更好的?恩里克,我编辑了它,甚至那是错误的。
  • @Jake:这就是Player 的实现。 GameObject 需要一个,除非您将其标记为纯虚拟。
【解决方案2】:

一些编译器要求对于每个签名,virtual 关键字只能在基类中指定一次。试试这个:

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

【讨论】:

  • 那些不会是 C++ 编译器。
  • @BenVoigt:在 2000 年左右的早期 VC++ 中曾经是这样。根据this 和其他来源,派生类中的虚拟关键字应该是可选的,但在现代符合标准的编译器中是无害的。
【解决方案3】:

如果你不需要公共的 GameObject::Initialise 方法是纯虚拟的,至少给它一个空的 body,像这样

class GameObject
{
public:
    void Initialise() {}
    ...
};

【讨论】:

  • 我在播放器中给它一个身体
【解决方案4】:

另一个猜想:你的代码中是否有任何 GameObject 的实例化?你有没有这样的:

GameObject go;

或类似的东西:

void foo( GameObject go );

或类似的东西:

GameObject bar();

或类似的东西:

vector<GameObject> all_my_objects;

【讨论】:

  • 没有,我不想这样做,这正是我将其抽象化的原因
  • 实例化可能是意外发生的,例如通过值而不是通过引用传递 GameObject 等。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-01
  • 2015-07-19
  • 2011-09-06
  • 2016-11-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多