Неопределенная ссылка на vtable - PullRequest
286 голосов
/ 17 июня 2010

При сборке моей программы на C ++ я получаю сообщение об ошибке

неопределенная ссылка на 'vtable ...

В чем причина этой проблемы? Как мне это исправить?


Так получилось, что я получаю сообщение об ошибке для следующего кода (рассматриваемый класс - CGameModule.), И я не могу понять, в чем проблема. Сначала я думал, что это связано с забвением придания виртуальной функции тела, но, насколько я понимаю, все здесь. Цепочка наследования немного длинна, но вот соответствующий исходный код. Я не уверен, какую еще информацию я должен предоставить.

Примечание: конструктор, где эта ошибка происходит, казалось бы.

Мой код:

class CGameModule : public CDasherModule {
 public:
  CGameModule(Dasher::CEventHandler *pEventHandler, CSettingsStore *pSettingsStore, CDasherInterfaceBase *pInterface, ModuleID_t iID, const char *szName)
  : CDasherModule(pEventHandler, pSettingsStore, iID, 0, szName)
  { 
      g_pLogger->Log("Inside game module constructor");   
      m_pInterface = pInterface; 
  }

  virtual ~CGameModule() {};

  std::string GetTypedTarget();

  std::string GetUntypedTarget();

  bool DecorateView(CDasherView *pView) {
      //g_pLogger->Log("Decorating the view");
      return false;
  }

  void SetDasherModel(CDasherModel *pModel) { m_pModel = pModel; }


  virtual void HandleEvent(Dasher::CEvent *pEvent); 

 private:



  CDasherNode *pLastTypedNode;


  CDasherNode *pNextTargetNode;


  std::string m_sTargetString;


  size_t m_stCurrentStringPos;


  CDasherModel *m_pModel;


  CDasherInterfaceBase *m_pInterface;
};

Наследуется от ...

class CDasherModule;
typedef std::vector<CDasherModule*>::size_type ModuleID_t;

/// \ingroup Core
/// @{
class CDasherModule : public Dasher::CDasherComponent {
 public:
  CDasherModule(Dasher::CEventHandler * pEventHandler, CSettingsStore * pSettingsStore, ModuleID_t iID, int iType, const char *szName);

  virtual ModuleID_t GetID();
  virtual void SetID(ModuleID_t);
  virtual int GetType();
  virtual const char *GetName();

  virtual bool GetSettings(SModuleSettings **pSettings, int *iCount) {
    return false;
  };

 private:
  ModuleID_t m_iID;
  int m_iType;
  const char *m_szName;
};

Который наследует от ....

namespace Dasher {
  class CEvent;
  class CEventHandler;
  class CDasherComponent;
};

/// \ingroup Core
/// @{
class Dasher::CDasherComponent {
 public:
  CDasherComponent(Dasher::CEventHandler* pEventHandler, CSettingsStore* pSettingsStore);
  virtual ~CDasherComponent();

  void InsertEvent(Dasher::CEvent * pEvent);
  virtual void HandleEvent(Dasher::CEvent * pEvent) {};

  bool GetBoolParameter(int iParameter) const;
  void SetBoolParameter(int iParameter, bool bValue) const;

  long GetLongParameter(int iParameter) const;
  void SetLongParameter(int iParameter, long lValue) const;

  std::string GetStringParameter(int iParameter) const;
  void        SetStringParameter(int iParameter, const std::string & sValue) const;

  ParameterType   GetParameterType(int iParameter) const;
  std::string     GetParameterName(int iParameter) const;

 protected:
  Dasher::CEventHandler *m_pEventHandler;
  CSettingsStore *m_pSettingsStore;
};
/// @}


#endif

Ответы [ 27 ]

2 голосов
/ 08 ноября 2015

Существует множество возможностей, вызывающих эту ошибку, и я уверен, что многие из них вызывают ошибку.В моем случае было другое определение того же класса из-за дублирования исходного файла.Этот файл был скомпилирован, но не связан, поэтому компоновщик жаловался на невозможность его найти.

Подводя итог, скажу, что если вы достаточно долго смотрели на класс и не видите, чтоэто может быть вызвано возможной синтаксической проблемой, ищите проблемы сборки, такие как отсутствующий файл или дублированный файл.

1 голос
/ 23 августа 2018

Я думаю, также стоит упомянуть, что вы также получите сообщение при попытке связать объект с любым классом , который имеет хотя бы один виртуальный метод и компоновщик не могу найти файл. Например:

Foo.hpp:

class Foo
{
public:
    virtual void StartFooing();
};

foo.cpp:

#include "Foo.hpp"

void Foo::StartFooing(){ //fooing }

Скомпилировано с:

g++ Foo.cpp -c

И main.cpp:

#include "Foo.hpp"

int main()
{
    Foo foo;
}

Скомпилировано и связано с:

g++ main.cpp -o main

выдает нашу любимую ошибку:

/ tmp / cclKnW0g.o: в функции main': main.cpp:(.text+0x1a): undefined reference to vtable для Foo 'collect2: ошибка: ld вернул 1 выход статус

Это произошло из-за моего непонимания:

  1. Vtable создается для класса во время компиляции

  2. Линкер не имеет доступа к vtable, который находится в Foo.o

1 голос
/ 21 июня 2012

Я получил эту ошибку в следующем сценарии

Рассмотрим случай, когда вы определили реализацию функций-членов класса в самом заголовочном файле.Этот заголовочный файл является экспортированным заголовком (другими словами, он может быть скопирован в какой-то общий файл / включен непосредственно в ваш код).Теперь вы решили отделить реализацию функций-членов от файла .cpp.После того как вы отделили / переместили реализацию в .cpp, в файле заголовка теперь есть только прототипы функций-членов внутри класса.После вышеупомянутых изменений, если вы строите свою кодовую базу, вы можете получить ошибку «undefined reference to 'vtable ...».

Чтобы исправить это, перед сборкой убедитесь, что вы удалили файл заголовка (для которого вывнесены изменения) в общий каталог / include.Также убедитесь, что вы изменили свой make-файл для размещения / добавления нового .o-файла, созданного из нового .cpp-файла, который вы только что создали.Когда вы выполните эти шаги, компилятор / компоновщик больше не будет жаловаться.

1 голос
/ 20 октября 2016

Я получил этот тип ошибки в ситуациях, когда я пытался связать объект, когда я получил ошибку создания, которая препятствовала добавлению объекта в архив.

Скажем, у меня есть libXYZ.a, который предполагалиметь bioseq.o в int, но это не так.

Я получил ошибку:

combineseq.cpp:(.text+0xabc): undefined reference to `vtable for bioseq'

Это совсем не так, как все вышеперечисленное.Я бы назвал этот отсутствующий объект в проблеме с архивом.

0 голосов
/ 14 августа 2017

Я получил эту ошибку, когда добавил второй класс к существующей паре источник / заголовок. Два заголовка класса в одном файле .h и определения функций для двух классов в одном файле .cpp.

Я делал это раньше успешно, с классами, предназначенными для тесного взаимодействия, но, похоже, мне что-то не понравилось в этот раз. Все еще не знаю что, но разделение их на один класс на единицу компиляции исправило это.


Неудачная попытка:

_gui_icondata.h:

#ifndef ICONDATA_H
#define ICONDATA_H

class Data;
class QPixmap;

class IconData
{
public:
    explicit IconData();
    virtual ~IconData();

    virtual void setData(Data* newData);
    Data* getData() const;
    virtual const QPixmap* getPixmap() const = 0;

    void toggleSelected();
    void toggleMirror();
    virtual void updateSelection() = 0;
    virtual void updatePixmap(const QPixmap* pixmap) = 0;

protected:
    Data* myData;
};

//--------------------------------------------------------------------------------------------------

#include "_gui_icon.h"

class IconWithData : public Icon, public IconData
{
    Q_OBJECT
public:
    explicit IconWithData(QWidget* parent);
    virtual ~IconWithData();

    virtual const QPixmap* getPixmap() const;
    virtual void updateSelection();
    virtual void updatePixmap(const QPixmap* pixmap);

signals:

public slots:
};

#endif // ICONDATA_H

_gui_icondata.cpp:

#include "_gui_icondata.h"

#include "data.h"

IconData::IconData()
{
    myData = 0;
}

IconData::~IconData()
{
    if(myData)
    {
        myData->removeIcon(this);
    }
    //don't need to clean up any more; this entire object is going away anyway
}

void IconData::setData(Data* newData)
{
    if(myData)
    {
        myData->removeIcon(this);
    }
    myData = newData;
    if(myData)
    {
        myData->addIcon(this, false);
    }
    updateSelection();
}

Data* IconData::getData() const
{
    return myData;
}

void IconData::toggleSelected()
{
    if(!myData)
    {
        return;
    }

    myData->setSelected(!myData->getSelected());
    updateSelection();
}

void IconData::toggleMirror()
{
    if(!myData)
    {
        return;
    }

    myData->setMirrored(!myData->getMirrored());
    updateSelection();
}

//--------------------------------------------------------------------------------------------------

IconWithData::IconWithData(QWidget* parent) :
    Icon(parent), IconData()
{
}

IconWithData::~IconWithData()
{
}

const QPixmap* IconWithData::getPixmap() const
{
    return Icon::pixmap();
}

void IconWithData::updateSelection()
{
}

void IconWithData::updatePixmap(const QPixmap* pixmap)
{
    Icon::setPixmap(pixmap, true, true);
}

Снова, добавление новой пары источник / заголовок и сокращение / вставка дословно класса IconWithData туда "просто сработало".

0 голосов
/ 30 сентября 2016

Также возможно, что вы получите сообщение типа

SomeClassToTest.host.o: In function `class1::class1(std::string const&)':
class1.hpp:114: undefined reference to `vtable for class1'
SomeClassToTest.host.o: In function `class1::~class1()':
class1.hpp:119: undefined reference to `vtable for class1'
collect2: error: ld returned 1 exit status
[link] FAILED: 'g++' '-o' 'stage/tests/SomeClassToTest' 'object/tests/SomeClassToTest.host.o' 'object/tests/FakeClass1.SomeClassToTest.host.o'

если вы забыли определить виртуальную функцию класса FakeClass1 при попытке связать модульный тест для другого класса SomeClass.

//class declaration in class1.h
class class1
{
    public:
    class1()
    {
    }
    virtual ~class1()
    {
    }
    virtual void ForgottenFunc();
};

А

//class definition in FakeClass1.h
//...
//void ForgottenFunc() {} is missing here

В этом случае я предлагаю вам еще раз проверить вашу подделку для class1. Вы, вероятно, обнаружите, что вы, возможно, забыли определить виртуальную функцию ForgottenFunc в вашем поддельном классе.

0 голосов
/ 12 июня 2015

Я получил эту ошибку только потому, что имя аргумента конструктора различалось в заголовочном файле и в файле реализации. Подпись конструктора

PointSet (const PointSet & pset, Parent * parent = 0);

и то, что я написал в реализации, началось с

PointSet (const PointSet & pest, Parent * parent)

таким образом я случайно заменил «pset» на «pest». Компилятор жаловался на этот и два других конструктора, в которых вообще не было ошибок. Я использую g ++ версии 4.9.1 под Ubuntu. И определение виртуального деструктора в этом производном классе не имеет значения (он определен в базовом классе). Я бы никогда не нашел эту ошибку, если бы не вставлял тела конструкторов в заголовочный файл, таким образом определяя их в классе.

...