尽管没有虚函数,但未定义引用Vtable

时间:2015-09-07 16:17:56

标签: 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::~angelic_wing()':
angelicwing.cpp:(.text+0x90): undefined reference to `vtable for angelic_wing'
collect2: error: ld returned 1 exit status

做了一些研究之后,似乎问题在于没有为基类中的虚函数定义一个主体。但是,出于以下原因,这个问题似乎并非如此:

  1. 这些是派生类的构造函数和析构函数, 因此不会在基地宣布或定义 类。
  2. 没有任何构造函数和析构函数在 派生类或基类声明/定义为虚拟。
  3. 我当然是在基类中使用虚函数。这是代码:

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

    如您所见,不是一个虚拟功能。我不确定发生了什么,但我遇到的大多数信息都说确保我已经定义了所有功能。但是,我无法进行双重检查,而且我确实似乎确定了所有这些内容。所以我的选择用完了。

    然而,有一件事我认为可能有一些相关性。我认为在同一个events.cpp文件中保留angelic_event类的虚函数和angelic_wing类的重写函数是个好主意。但是,在我这样做之后,我怀疑,也许是因为一些奇怪的巧合,这导致了对于'angelic_wing'的vtable的未定义引用。错误。

    因此我将重写的函数移动到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

1 个答案:

答案 0 :(得分:1)

派生类会覆盖基类中的至少两个虚函数:user_eventflag_exit。缺少virtual说明符并不重要,这些都是虚函数。并且flag_exit永远不会被定义。

如果第一个虚函数未定义,您将经常获得对vtable"的未定义引用。错误。