【问题标题】:Despite no Virtual Functions, Undefined reference to Vtable尽管没有虚函数,对 Vtable 的未定义引用
【发布时间】:2015-09-07 16:17:55
【问题描述】:

我有一个基类和一个派生类,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. 没有任何构造函数和析构函数 派生类或基类被声明/定义为虚拟。

当然,我在基类中使用虚函数。代码如下:

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_event 类的虚函数和 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 位兼容性文件等。

我必须说,这对我来说已经变成了一个真正的头痛。希望你们更有经验的人能告诉我我做错了什么,或者可能是一种前进的方法。

非常感谢您的宝贵时间, 何塞·路易斯·A·努涅斯

【问题讨论】:

  • 很多很多骗子。不言自明的错误也是:您没有虚拟~angelic_wing,因为您没有虚拟~angelic_event。给你的多态基础一个虚拟析构函数,一切都会好起来的。
  • 另外,通常最好先尝试做一个简化的测试用例。这让人们更容易回答,而且在这种情况下,您很可能会自己发现问题!
  • 我投票决定将此问题作为题外话结束,因为这与 minimal example 证明实际问题相去甚远。同样正如 LRIO 所说,解决起来很简单。
  • 我会第二个 @πάνταῥεῖ 。就目前而言,事实证明问题与大多数这些类型几乎相同。它可能具有建设性的唯一方法是指出缺少虚拟说明符并不意味着该函数不是虚拟的。非常感谢,伙计们。

标签: c++ inheritance linker g++ vtable


【解决方案1】:

您的派生类至少覆盖了基类中的两个虚函数:user_eventflag_exit。缺少 virtual 说明符无关紧要,这些是虚函数。而flag_exit 从未定义过。

如果第一个虚函数未定义,您经常会得到“未定义对 vtable 的引用”的错误。

【讨论】:

  • 非常感谢,n.m!我现在觉得有点傻,我承认。但与此同时,我很高兴这个问题原来如此微不足道。有时,这是最简单的事情。谢谢!
猜你喜欢
  • 2020-04-09
  • 2021-12-13
  • 1970-01-01
  • 2012-08-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多