C++ 尽管没有虚拟函数,但未定义对Vtable的引用

C++ 尽管没有虚拟函数,但未定义对Vtable的引用,c++,inheritance,linker,g++,vtable,C++,Inheritance,Linker,G++,Vtable,我有一个基类和一个派生类,angelic_wing(派生类)和angelic_event(基类)。编译时,会出现以下两个错误: /tmp/ccG6KlZF.o: In function `angelic_wing::angelic_wing()': angelicwing.cpp:(.text+0x20): undefined reference to `vtable for angelic_wing' /tmp/ccG6KlZF.o: In function `angelic_wing::~a

我有一个基类和一个派生类,angelic_wing(派生类)和angelic_event(基类)。编译时,会出现以下两个错误:

/tmp/ccG6KlZF.o: In function `angelic_wing::angelic_wing()':
angelicwing.cpp:(.text+0x20): undefined reference to `vtable for angelic_wing'
/tmp/ccG6KlZF.o: In function `angelic_wing::~angelic_wing()':
angelicwing.cpp:(.text+0x90): undefined reference to `vtable for angelic_wing'
collect2: error: ld returned 1 exit status
做了一些研究之后,问题似乎与不在基类中定义虚函数的主体有关。然而,由于以下原因,该问题似乎并非如此:

  • 这些是派生类的构造函数和析构函数, 因此,不会在基础中声明或定义 班级
  • 中的构造函数和析构函数都不起作用 派生类或基类被声明/定义为虚拟类
  • 当然,我在基类中使用虚拟函数。代码如下:

    class angelic_event{
    public:
      angelic_event();
      ~angelic_event();
    
      virtual void events(SDL_Event *event);
      virtual void input_focus();
      virtual void input_blur();
    
      virtual void key_down(SDLKey sym, SDLMod mod, Uint16 unicode);
      virtual void key_up(SDLKey sym, SDLMod mod, Uint16 unicode);
    
      virtual void mouse_focus();
      virtual void mouse_blur();
    
      virtual void mouse_move(int x, int y, int rx, int ry, int left, int right, int middle);
      virtual void mouse_wheel(int up, int down);
    
      virtual void ml_button_down(int x, int y);
      virtual void ml_button_up(int x, int y);
    
      virtual void mr_button_down(int x, int y);
      virtual void mr_button_up(int x, int y);
    
      virtual void mm_button_down(int x, int y);
      virtual void mm_button_up(int x, int y);
    
      virtual void joy_axis(Uint8 which, Uint8 axis, Sint16 value);
      virtual void joy_button_down(Uint8 which, Uint8 button);
      virtual void joy_button_up(Uint8 which, Uint8 button);
      virtual void joy_hat(Uint8 which, Uint8 hat, Uint8 value);
      virtual void joy_ball(Uint8 which, Uint8 ball, Sint16 rx, Sint16 ry);
    
      virtual void minimize();
      virtual void restore();
    
      virtual void resize(int w, int h);
      virtual void expose();
      virtual void flag_exit();
    
      virtual void user_event(Uint8 type, int code, void *data1, void *data2);
    };
    
    然而,据我所知,我已经在events.cpp文件中定义了所有这些函数。还要注意,类的构造函数和析构函数都不是虚函数

    另一方面,我的派生类根本不声明任何虚函数。以下是代码:

    class angelic_wing : angelic_event{
      int game_state;
      int current_state;
    
      angelic_clock game_clock;
      int newtime;
      int oldtime;
    
      SDL_Event event;
      SDL_Surface *screen;
    private:
      void init_bootstrap();
      void init_mainmenu();
      void init_pausemenu();
      void init_gameover();
      void init_gamewin();
      void init_gamecredits();
      void init_gameproper();
    private:
      void flag_exit();
      void user_event(Uint8 type, int code, void *data1, void *data2);
    public:
      angelic_wing();
      ~angelic_wing();
    
      int execute();
      int initiate();
      int destruct();
    
      int process_event(SDL_Event *event);
      int update();
      int render();
    
      int game_state_init(int current_state);
      int check_time(float elapsed);
    };
    
    正如您所看到的,没有一个虚拟函数。我不确定发生了什么,但我遇到的大多数信息都表明我已经定义了所有函数。然而,我不能一直重复检查,而且似乎我已经定义了所有这些。所以我没有选择了

    然而,我认为有一件事可能与此相关。我认为将angelic_事件类的虚拟函数和angelic_wing类的重写函数保留在同一events.cpp文件中是个好主意。然而,做了这件事之后,我怀疑,也许是出于某种奇怪的巧合,这导致了“未定义的对‘vtable for angelic_-wing’的引用”错误

    因此,我将重写的函数移到了angelicwing.cpp文件中,但没有用。不管怎样,这个问题仍然存在

    下面是events.cpp文件的完整代码,以防你们发现我遗漏了什么:

    #include "events.hpp"
    #include "angelicwing.hpp"
    
    angelic_event :: angelic_event(){}
    angelic_event :: ~angelic_event(){}
    
    void angelic_event :: events(SDL_Event *event)
    {
      switch(event->type){
      case SDL_ACTIVEEVENT:
        switch(event->active.state){
        case SDL_APPMOUSEFOCUS:
          if(event->active.gain){
            mouse_focus();
          } else {
            mouse_blur();
          } break;
        case SDL_APPINPUTFOCUS:
          if(event->active.gain){
            input_focus();
          } else {
            input_blur();
          } break;
        case SDL_APPACTIVE:
          if(event->active.gain){
            restore();
          } else {
            minimize();
          } break;
        } break;
      case SDL_KEYDOWN:
        key_down(event->key.keysym.sym, event->key.keysym.mod, event->key.keysym.unicode);
        break;
      case SDL_KEYUP:
        key_up(event->key.keysym.sym, event->key.keysym.mod, event->key.keysym.unicode);
      case SDL_MOUSEMOTION:
        mouse_move(event->motion.x, event->motion.y, event->motion.xrel, event->motion.yrel,
                   (event->motion.state&SDL_BUTTON(SDL_BUTTON_LEFT))!=0,
                   (event->motion.state&SDL_BUTTON(SDL_BUTTON_RIGHT))!=0,
                   (event->motion.state&SDL_BUTTON(SDL_BUTTON_MIDDLE))!=0);
        break;
      case SDL_MOUSEBUTTONDOWN:
        switch(event->button.button){
        case SDL_BUTTON_LEFT:
          ml_button_down(event->button.x, event->button.y);
          break;
        case SDL_BUTTON_RIGHT:
          mr_button_down(event->button.x, event->button.y);
          break;
        case SDL_BUTTON_MIDDLE:
          mm_button_down(event->button.x, event->button.y);
          break;
        } break;
      case SDL_MOUSEBUTTONUP:
        switch(event->button.button){
        case SDL_BUTTON_LEFT:
          ml_button_up(event->button.x, event->button.y);
          break;
        case SDL_BUTTON_RIGHT:
          mr_button_up(event->button.x, event->button.y);
          break;
        case SDL_BUTTON_MIDDLE:
          mm_button_up(event->button.x, event->button.y);
          break;
        } break;
      case SDL_JOYAXISMOTION:
        joy_axis(event->jaxis.which, event->jaxis.axis, event->jaxis.value);
        break;
      case SDL_JOYBALLMOTION:
        joy_ball(event->jball.which, event->jball.ball, event->jball.xrel, event->jball.yrel);
        break;
      case SDL_JOYHATMOTION:
        joy_hat(event->jhat.which, event->jhat.hat, event->jhat.value);
        break;
      case SDL_JOYBUTTONDOWN:
        joy_button_down(event->jbutton.which, event->jbutton.button);
        break;
      case SDL_JOYBUTTONUP:
        joy_button_up(event->jbutton.which, event->jbutton.button);
        break;
      case SDL_QUIT:
        flag_exit();
        break;
      case SDL_SYSWMEVENT:
        // ignore?
        break;
      case SDL_VIDEORESIZE:
        resize(event->resize.w, event->resize.h);
        break;
      case SDL_VIDEOEXPOSE:
        expose();
        break;
      default:
        user_event(event->user.type, event->user.code, event->user.data1, event->user.data2);
        break;
      };
    }
    
    void angelic_event :: input_focus(){}
    void angelic_event :: input_blur(){}
    void angelic_event :: key_down(SDLKey sym, SDLMod mod, Uint16 unicode){}
    void angelic_event :: key_up(SDLKey sym, SDLMod mod, Uint16 unicode){}
    void angelic_event :: mouse_focus(){}
    void angelic_event :: mouse_blur(){}
    void angelic_event :: mouse_move(int x, int y, int rx, int ry, int left, int right, int middle){}
    void angelic_event :: mouse_wheel(int up, int down){}
    void angelic_event :: ml_button_down(int x, int y){}
    void angelic_event :: ml_button_up(int x, int y){}
    void angelic_event :: mr_button_down(int x, int y){}
    void angelic_event :: mr_button_up(int x, int y){}
    void angelic_event :: mm_button_down(int x, int y){}
    void angelic_event :: mm_button_up(int x, int y){}
    void angelic_event :: joy_axis(Uint8 which, Uint8 axis, Sint16 value){}
    void angelic_event :: joy_button_down(Uint8 which, Uint8 button){}
    void angelic_event :: joy_button_up(Uint8 which, Uint8 button){}
    void angelic_event :: joy_hat(Uint8 which, Uint8 hat, Uint8 value){}
    void angelic_event :: joy_ball(Uint8 which, Uint8 ball, Sint16 rx, Sint16 ry){}
    void angelic_event :: minimize(){}
    void angelic_event :: restore(){}
    void angelic_event :: resize(int w, int h){}
    void angelic_event :: expose(){}
    void angelic_event :: flag_exit(){}
    void angelic_event :: user_event(Uint8 type, int code, void *data1, void *data2){}
    
    void angelic_wing :: user_event(Uint8 type, int code, void *data1, void *data2)
    {
      switch(code){
      case CHANGE_GAME_MODE:
        game_state = *((int *)data1);
        break;
      default:
        break;
      }
    }
    
    另外,如果有帮助,我应该告诉你一些我的系统。我使用的是GCC版本4.8.2(尽管我是使用g++命令编译的)。我在64位系统上运行Slackware 14.1版,没有32位兼容文件,等等

    我必须说,这对我来说真是一个头痛的问题。希望你们这些更有经验的人能告诉我我做错了什么,或者是一种前进的方式

    非常感谢您抽出时间,
    Jose Luis A.Nunez

    您的派生类重写基类中至少两个虚拟函数:
    user\u event
    flag\u exit
    。缺少
    virtual
    说明符无关紧要,这些都是虚拟函数。而且从未定义退出标志


    如果第一个虚拟函数未定义,则通常会出现“未定义对vtable的引用”错误。

    多次重复。这也是一个不言自明的错误:您没有虚拟的
    ~angelic\u wing
    ,因为您没有虚拟的
    ~angelic\u事件。给你的多态库一个虚拟析构函数,一切都会好起来的。另外,通常最好先做一个简化的测试用例。这使得人们更容易回答问题,在这种情况下,你很可能会自己发现问题!我投票决定把这个问题作为离题题来结束,因为这远远不能说明实际问题。同样,正如LRIO所说,这是一个很容易解决的问题。我将第二个@πάνταῥεῖ . 目前的情况是,问题几乎与这些类型中的大多数相同。唯一具有建设性的方法是指出缺少虚拟说明符并不意味着函数不是虚拟的。非常感谢,伙计们。非常感谢,n.m!我承认,我现在觉得有点傻。但与此同时,我很高兴这个问题变得如此琐碎。有时候,这是最简单的事情。非常感谢。