对具有嵌套类的 vtable 的未定义引用

Undefined reference to vtable with nested class

提问人:Leandro Oliveira Rezende 提问时间:5/6/2017 最后编辑:Leandro Oliveira Rezende 更新时间:5/9/2017 访问量:713

问:

当我尝试编译以下代码时:

Alien::Action::Action(ActionType type, float x, float y) {
    Action::type = type;
    pos = Vec2(x, y);
}

Alien::Alien(float x, float y, int nMinions) {
    srand(time(NULL));
    sp = Sprite("img/alien.png");
    box = Rect(x, y, sp.GetWidth(), sp.GetHeight());
    box.x = x - box.h/2;
    box.y = y - box.w/2;
    hitpoints = 100;
    speed.x = 0.5;
    speed.y = 0.5;
    minionArray = std::vector<Minion>();
    for(int i = 0; i < nMinions; i++) {
        int a = rand()%501;
        float b = a/1000.0;
        float c = b+1;
        minionArray.emplace_back(Minion(get(), i*(360/nMinions), c));
    }
    taskQueue = std::queue<Action>();
}

IDE (Eclipse) 给出以下错误消息:“undefined reference to 'vtable for Alien'”(代码第 6 行)。由于 Alien 内部没有虚拟方法,我不知道错误的原因。以下是 Alien 的头文件:

#ifndef ALIEN_H_
#define ALIEN_H_

#include "GameObject.h"

class Alien: public GameObject {
private:
    class Action {
    public:
        enum ActionType {MOVE, SHOOT};
        ActionType type;
        Action(ActionType type, float x, float y);
        Vec2 pos;
    };
    int hitpoints;
    std::queue<Action> taskQueue;
    std::vector<Minion> minionArray;
public:
    Alien(float x, float y, int nMinions);
    ~Alien();
    void Update(float dt);
    void Render();
    Alien* get();
    bool IsDead();
};

#endif

GameObject 的代码为:

#include "GameObject.h"
#include "InputManager.h"
#include "Camera.h"
#include "State.h"

    GameObject::~GameObject() {

    }

    GameObject* GameObject::get() {
        return this;
    }

    Minion::~Minion() {

    }

    Minion::Minion(GameObject* minionCenter, float arcOffset, float minionSize) {
        sp = Sprite("img/minion.png");
        center = minionCenter;
        translation = arcOffset;
        box = Rect(center->box.GetCenter().x+(cos(translation*M_PI/180)*200)-(sp.GetWidth()/2),
                   center->box.GetCenter().y+(sin(translation*M_PI/180)*200)-(sp.GetHeight()/2),
                   sp.GetWidth(), sp.GetHeight());
    }

    void Minion::Shoot(Vec2 pos) {
        State::AddObject(new BulletWheel(box.GetCenter().x, box.GetCenter().y, center->box.GetCenter().GetDX(pos.x),
                                         center->box.GetCenter().GetDY(pos.y), center->box.GetCenter().GetDS(pos), 0.3,
                                         translation, center->box.GetCenter(), "img/minionbullet1.png"));
    }

    void Minion::Update(float dt) {
        if(translation < 360)
            translation += 0.03*dt;
        else
            translation += 0.03*dt-360;
        /*rotation = translation-90;*/
        if(rotation < 360)
            rotation += 0.15*dt;
        else
            rotation += 0.15*dt-360;
        box.x = center->box.GetCenter().x+(200*cos((translation)*M_PI/180))-(box.w/2);
        box.y = center->box.GetCenter().y+(200*sin((translation)*M_PI/180))-(box.h/2);
    }

    void Minion::Render() {
        sp.Render(box.x - Camera::GetInstance().pos.x, box.y - Camera::GetInstance().pos.y, rotation);
    }

    bool Minion::IsDead() {
        return false;
    }

    Bullet::Bullet(float x, float y, float dx, float dy, float maxDistance, float speed, std::string sprite) {
        sp = Sprite(sprite);
        box = Rect(x-(sp.GetWidth()/2), y-(sp.GetHeight()/2), sp.GetWidth(), sp.GetHeight());
        Bullet::speed = Vec2(speed*(dx/maxDistance), speed*(dy/maxDistance));
        distanceLeft = maxDistance;
        rotation = atan2(dy, dx)*(180/M_PI);
    }

    void Bullet::Update(float dt) {
        if(distanceLeft > 0) {
            box.x += speed.x*dt;
            box.y += speed.y*dt;
            distanceLeft -= pow(pow(speed.x*dt,2)+pow(speed.y*dt,2),0.5);
        }
    }

    void Bullet::Render() {
        sp.Render(box.x - Camera::GetInstance().pos.x, box.y - Camera::GetInstance().pos.y, rotation);
    }

    bool Bullet::IsDead() {
        return (distanceLeft < 1) ? true : false;
    }

    Bullet* Bullet::get() {
        return this;
    }

    BulletWheel::BulletWheel(float x, float y, float dx, float dy, float maxDistance, float speed, float arcOffset, Vec2 center, std::string sprite) {
        sp = Sprite(sprite);
        sp.SetScaleX(2);
        sp.SetScaleY(2);
        box = Rect(x-(sp.GetWidth()/2), y-(sp.GetHeight()/2), sp.GetWidth(), sp.GetHeight());
        BulletWheel::speed = Vec2(speed*(dx/maxDistance), speed*(dy/maxDistance));
        distanceLeft = maxDistance;
        rotation = atan2(dy, dx)*(180/M_PI);
        translation = arcOffset;
        BulletWheel::center = center;
    }

    void BulletWheel::Update(float dt) {
        if(translation < 360)
            translation += 0.1*dt;
        else
            translation += 0.1*dt-360;
        if(distanceLeft > 0.01) {
            center.x += speed.x*dt;
            center.y += speed.y*dt;
            box.x = center.x+(200*cos((translation)*M_PI/180))-(box.w/2);
            box.y = center.y+(200*sin((translation)*M_PI/180))-(box.h/2);
            distanceLeft -= pow(pow(speed.x*dt,2)+pow(speed.y*dt,2),0.5);
        }
    }

    void BulletWheel::Render() {
        sp.Render(box.x - Camera::GetInstance().pos.x, box.y - Camera::GetInstance().pos.y, rotation);
    }

    bool BulletWheel::IsDead() {
        return distanceLeft < 1;
    }

    BulletWheel* BulletWheel::get() {
        return this;
    }

其头文件为: #ifndef GAMEOBJECT_H_ #define GAMEOBJECT_H_

#include "Sprite.h"
#include "Rect.h"
#include "Vec2.h"
#include <queue>
#include <vector>
#include <cmath>
#include <ctime>

class GameObject{
private:

public:
    virtual ~GameObject();
    virtual void Update(float dt) = 0;
    virtual void Render() = 0;
    virtual bool IsDead() = 0;
    virtual GameObject* get();
    int rotation = 0;
    int translation = 0;
    Sprite sp = Sprite();
    Vec2 speed = Vec2();
    Rect box = Rect();
};

class Minion : public GameObject {
private:
    GameObject* center;

public:
    Minion(GameObject* minionCenter, float arcOffset, float minionSize = 1);
    ~Minion();
    void Shoot(Vec2 pos);
    void Update(float dt);
    void Render();
    bool IsDead();
    Minion* get();
};

class Bullet : public GameObject {
private:
    float distanceLeft;
public:
    Bullet(float x, float y, float dx, float dy, float maxDistance, float speed, std::string sprite);
    void Update(float dt);
    void Render();
    bool IsDead();
    Bullet* get();
};

class BulletWheel : public GameObject {
private:
    float distanceLeft;
    Vec2 center;
public:
    BulletWheel(float x, float y, float dx, float dy, float maxDistance, float speed, float arcOffset, Vec2 center, std::string sprite);
    void Update(float dt);
    void Render();
    bool IsDead();
    BulletWheel* get();
};

#endif /* GAMEOBJECT_H_ */

有GameObject的虚拟函数,在Alien.cpp中声明:

void Alien::Update(float dt) {
    if(rotation > 0)
        rotation -= 0.1*dt;
    else
        rotation -= 0.1*dt+360;
    if(InputManager::GetInstance().MousePress(RIGHT_MOUSE_BUTTON)) {
        taskQueue.push(Action(Action::MOVE,(InputManager::GetInstance().GetMouseX() + Camera::GetInstance().pos.x - (box.w/2)),
                                           (InputManager::GetInstance().GetMouseY() + Camera::GetInstance().pos.y - (box.h/2))));
    }
    if(InputManager::GetInstance().MousePress(LEFT_MOUSE_BUTTON)) {
        taskQueue.push(Action(Action::SHOOT,(InputManager::GetInstance().GetMouseX() + Camera::GetInstance().pos.x),
                                            (InputManager::GetInstance().GetMouseY() + Camera::GetInstance().pos.y)));
    }
    if(taskQueue.size() > 0) {
        Vec2 pos = taskQueue.front().pos;
        if(taskQueue.front().type == Action::MOVE) {
            float cos = (box.GetDX(pos.x)/box.GetDS(pos));
            float sin = (box.GetDY(pos.y)/box.GetDS(pos));
            if(cos != cos) {
                cos = 0;
            }
            if(sin != sin) {
                sin = 0;
            }
            if((box.x+speed.x*cos*dt > pos.x && pos.x > box.x) || (box.x+speed.x*cos*dt < pos.x && pos.x < box.x)) {
                box.x = pos.x;
            }
            else {
                box.x += speed.x*cos*dt;
            }
            if((box.y+speed.y*sin*dt > pos.y && pos.y > box.y) || (box.y+speed.y*sin*dt < pos.y && pos.y < box.y)) {
                box.y = pos.y;
            }
            else {
                box.y += speed.y*sin*dt;
            }
            if(box.x == pos.x && box.y == pos.y) {
                taskQueue.pop();
            }
        }
        else {
            for(unsigned i = 0; i < minionArray.size(); i++) {
            minionArray.at(i).Shoot(pos);
            taskQueue.pop();
            }
        }
    }
    for(unsigned i = 0; i < minionArray.size(); i++) {
        minionArray.at(i).Update(dt);
    }
}

void Alien::Render() {
    sp.Render(box.x - Camera::GetInstance().pos.x, box.y - Camera::GetInstance().pos.y, rotation);
    if(minionArray.size() > 0) {
        for(unsigned i = 0; i < Alien::minionArray.size(); i++) {
            minionArray.at(i).Render();
        }
    }
}

bool Alien::IsDead() {
    return (Alien::hitpoints <= 0);
}

编辑:外星人的破坏者失踪了。

C++ C++11 嵌套 未定义引用

评论

0赞 Peter 5/6/2017
什么?如果它被设计为用作基类,它很可能具有虚拟函数。但是,更一般地说,您没有提供足够的信息,需要提供最小的可重现示例GameObject
0赞 aschepler 5/6/2017
任何重写基类虚拟函数的函数都自动是虚拟函数。这包括析构函数。
0赞 Leandro Oliveira Rezende 5/6/2017
GameObject 实际上是一个基类。 @aschepler:那么,我该如何解决这个问题呢?
0赞 aschepler 5/6/2017
定义所有虚拟功能。
0赞 Leandro Oliveira Rezende 5/6/2017
我不知道我没有声明什么函数

答:

0赞 zeus_masta_funk 5/6/2017 #1

派生自 的所有类都必须在 中定义所有纯虚函数。就您而言,这是:GameObjectGameObject

virtual void Update(float dt) = 0;
virtual void Render() = 0;
virtual bool IsDead() = 0;

这是一个类似的问题,有更多信息。希望这有帮助!

评论

0赞 Leandro Oliveira Rezende 5/6/2017
但这三个功能都是在《异形》中定义的。我会在问题中对它们进行索引
0赞 zeus_masta_funk 5/8/2017
你能发布编译器的实际输出吗?此外,您应该在派生类中使用说明符 - 这可能有助于获得更好的错误消息。此外,还可以通过在析构函数上使用说明符来消除某些代码。overridedefaultGameObject