title: Despite no Virtual Functions, Undefined reference to Vtable
body: <p>I have a base class and a derived class, angelic_wing(the derived one), and angelic_event(the base one). When I compile, I get the following two errors:</p>
  
  <pre><code>/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
  </code></pre>
  
  <p>Having done some research, it would seem that the issue pertains to not defining a body for a virtual function in the base class. However, this issue doesn't seem to be the case for the following reasons:</p>
  
  <ol>
  <li>These are constructor and destructor functions of the derived class,
  and therefore would not have been declared nor defined in the base
  class.</li>
  <li>None of the constructor and destructor functions in either the
  derived class or the base class are declared/defined as virtual.</li>
  </ol>
  
  <p>I am, of course, using virtual functions in the base class. Here is the code:</p>
  
  <pre><code>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);
  };
  </code></pre>
  
  <p>As far as I can tell, however, I have defined all of these functions in my events.cpp file. Also note that neither constructor nor destructor of the class is a virtual function.</p>
  
  <p>My derived class, on the other hand, does not declare any virtual functions at all. Here is the code for that:</p>
  
  <pre><code>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);
  };
  </code></pre>
  
  <p>As you can see, not a single virtual function. I'm not sure what is going on, but most information that I have come across has said to make sure that I've defined all the functions. I can't keep double checking, however, and it really does seem that I've defined all of them. So I'm running out of options.</p>
  
  <p>There is one thing that I thought might have some relevance, however. I thought that it would be a good idea to keep the virtual functions for the angelic_event class and the overridden functions of the angelic_wing class in the same events.cpp file. Having done this, however, I suspected that, maybe by some strange coincidence, this was causing the 'undefined reference to `vtable for angelic_wing' error.</p>
  
  <p>I thus moved the overridden function into the angelicwing.cpp file, but to no avail. The issue persisted regardless.</p>
  
  <p>Here is the code for the events.cpp file in its entirety, in case you guys can catch something I've missed:</p>
  
  <pre><code>#include "events.hpp"
  #include "angelicwing.hpp"
  
  angelic_event :: angelic_event(){}
  angelic_event :: ~angelic_event(){}
  
  void angelic_event :: events(SDL_Event *event)
  {
    switch(event-&gt;type){
    case SDL_ACTIVEEVENT:
      switch(event-&gt;active.state){
      case SDL_APPMOUSEFOCUS:
        if(event-&gt;active.gain){
          mouse_focus();
        } else {
          mouse_blur();
        } break;
      case SDL_APPINPUTFOCUS:
        if(event-&gt;active.gain){
          input_focus();
        } else {
          input_blur();
        } break;
      case SDL_APPACTIVE:
        if(event-&gt;active.gain){
          restore();
        } else {
          minimize();
        } break;
      } break;
    case SDL_KEYDOWN:
      key_down(event-&gt;key.keysym.sym, event-&gt;key.keysym.mod, event-&gt;key.keysym.unicode);
      break;
    case SDL_KEYUP:
      key_up(event-&gt;key.keysym.sym, event-&gt;key.keysym.mod, event-&gt;key.keysym.unicode);
    case SDL_MOUSEMOTION:
      mouse_move(event-&gt;motion.x, event-&gt;motion.y, event-&gt;motion.xrel, event-&gt;motion.yrel,
                 (event-&gt;motion.state&amp;SDL_BUTTON(SDL_BUTTON_LEFT))!=0,
                 (event-&gt;motion.state&amp;SDL_BUTTON(SDL_BUTTON_RIGHT))!=0,
                 (event-&gt;motion.state&amp;SDL_BUTTON(SDL_BUTTON_MIDDLE))!=0);
      break;
    case SDL_MOUSEBUTTONDOWN:
      switch(event-&gt;button.button){
      case SDL_BUTTON_LEFT:
        ml_button_down(event-&gt;button.x, event-&gt;button.y);
        break;
      case SDL_BUTTON_RIGHT:
        mr_button_down(event-&gt;button.x, event-&gt;button.y);
        break;
      case SDL_BUTTON_MIDDLE:
        mm_button_down(event-&gt;button.x, event-&gt;button.y);
        break;
      } break;
    case SDL_MOUSEBUTTONUP:
      switch(event-&gt;button.button){
      case SDL_BUTTON_LEFT:
        ml_button_up(event-&gt;button.x, event-&gt;button.y);
        break;
      case SDL_BUTTON_RIGHT:
        mr_button_up(event-&gt;button.x, event-&gt;button.y);
        break;
      case SDL_BUTTON_MIDDLE:
        mm_button_up(event-&gt;button.x, event-&gt;button.y);
        break;
      } break;
    case SDL_JOYAXISMOTION:
      joy_axis(event-&gt;jaxis.which, event-&gt;jaxis.axis, event-&gt;jaxis.value);
      break;
    case SDL_JOYBALLMOTION:
      joy_ball(event-&gt;jball.which, event-&gt;jball.ball, event-&gt;jball.xrel, event-&gt;jball.yrel);
      break;
    case SDL_JOYHATMOTION:
      joy_hat(event-&gt;jhat.which, event-&gt;jhat.hat, event-&gt;jhat.value);
      break;
    case SDL_JOYBUTTONDOWN:
      joy_button_down(event-&gt;jbutton.which, event-&gt;jbutton.button);
      break;
    case SDL_JOYBUTTONUP:
      joy_button_up(event-&gt;jbutton.which, event-&gt;jbutton.button);
      break;
    case SDL_QUIT:
      flag_exit();
      break;
    case SDL_SYSWMEVENT:
      // ignore?
      break;
    case SDL_VIDEORESIZE:
      resize(event-&gt;resize.w, event-&gt;resize.h);
      break;
    case SDL_VIDEOEXPOSE:
      expose();
      break;
    default:
      user_event(event-&gt;user.type, event-&gt;user.code, event-&gt;user.data1, event-&gt;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;
    }
  }
  </code></pre>
  
  <p>Also, in case it might help, I should tell you a little bit about my system. I'm using GCC Version 4.8.2 (although I am compiling with the g++ command). I'm running Slackware Version 14.1 on a 64-bit system, sans the 32-bit compatibility files, etc.</p>
  
  <p>I must say, this has turned into a real head scratcher for me. Hopefully, you more experienced fellows can show me what I'm doing wrong, or perhaps a way to move forward.</p>
  
  <p>Thanks very much for your time,
  Jose Luis A. Nunez</p>