Search code examples
c++inheritancelinkerg++vtable

Despite no Virtual Functions, Undefined reference to Vtable


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:

/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

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:

  1. These are constructor and destructor functions of the derived class, and therefore would not have been declared nor defined in the base class.
  2. None of the constructor and destructor functions in either the derived class or the base class are declared/defined as virtual.

I am, of course, using virtual functions in the base class. Here is the 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);
};

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.

My derived class, on the other hand, does not declare any virtual functions at all. Here is the code for that:

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

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.

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.

I thus moved the overridden function into the angelicwing.cpp file, but to no avail. The issue persisted regardless.

Here is the code for the events.cpp file in its entirety, in case you guys can catch something I've missed:

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

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.

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.

Thanks very much for your time, Jose Luis A. Nunez


Solution

  • Your derived class overrides at least two virtual functions from the base class: user_event and flag_exit. Lack of the virtual specifier is immaterial, these are virtual functions. And flag_exit is never defined.

    If the first virtual function is left undefined, you will often get the "undefined reference to vtable" error.