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

时间:2017-05-05 22:46:45

标签: c++ class c++11 nested undefined-reference

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

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)提供以下错误消息:&#34;未定义引用&#39; vtable for Alien&#39;&#34; (代码第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);
}
编辑:外星人的破坏者失踪了。

1 个答案:

答案 0 :(得分:0)

GameObject派生的所有类必须在GameObject中定义所有纯虚函数。在您的情况下,这是:

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

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