c++ for - Undefined reference to vtable




14 Answers

The GCC FAQ has an entry on it:

The solution is to ensure that all virtual methods that are not pure are defined. Note that a destructor must be defined even if it is declared pure-virtual [class.dtor]/7.

destructor constructor

So, I'm getting the infamously horrible

undefined reference to 'vtable...

error for the following code (The class in question is CGameModule.) and I cannot for the life of me understand what the problem is. At first, I thought it was related to forgetting to give a virtual function a body, but as far as I understand, everything is all here. The inheritance chain is a little long, but here is the related source code. I'm not sure what other information I should provide.

Note: The constructor is where this error is happening, it'd seem.

My code:

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

Inherits from...

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

Which inherits from....

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



So, I've figured out the issue and it was a combination of bad logic and not being totally familiar with the automake/autotools world. I was adding the correct files to my Makefile.am template, but I wasn't sure which step in our build process actually created the makefile itself. So, I was compiling with an old makefile that had no idea about my new files whatsoever.

Thanks for the responses and the link to the GCC FAQ. I will be sure to read that to avoid this problem occurring for a real reason.




I simply got this error because my cpp file was not in the makefile.




I just ran into another cause for this error that you can check for.

The base class defined a pure virtual function as:

virtual int foo(int x = 0);

And the subclass had

int foo(int x) override;

The problem was the typo that the "=0" was supposed to be outside of the parenthesis:

virtual int foo(int x) = 0;

So, in case you're scrolling this far down, you probably didn't find the answer - this is something else to check for.




This can happen quite easily if you forget to link to the object file that has the definition.




Ok, the solution to this is that you may have missed out on the definition. See the example below to avoid the vtable compiler error:

// In the CGameModule.h

class CGameModule
{
public:
    CGameModule();
    ~CGameModule();

    virtual void init();
};

// In the CGameModule.cpp

#include "CGameModule.h"

CGameModule::CGameModule()
{

}

CGameModule::~CGameModule()
{

}

void CGameModule::init()    // Add the definition
{

}



  • Are you sure that CDasherComponent has a body for the destructor? It's definitely not here - the question is if it is in the .cc file.
  • From a style perspective, CDasherModule should explicitly define its destructor virtual.
  • It looks like CGameModule has an extra } at the end (after the }; // for the class).
  • Is CGameModule being linked against the libraries that define CDasherModule and CDasherComponent?



This was the first search result for me so I thought I'd add another thing to check: make sure the definition of virtual functions are actually on the class. In my case, I had this:

Header file:

class A {
 public:
  virtual void foo() = 0;
};

class B : public A {
 public:
  void foo() override;
};

and in my .cc file:

void foo() {
  ...
}

This should read

void B::foo() {
}



So many answers here but none of them seemed to have covered what my problem was. I had the following:


class I {
    virtual void Foo()=0;
};

And in another file (included in the compilation and linking, of course)

class C : public I{
    void Foo() {
        //bar
    }
};

Well this didn't work and I got the error everyone is talking about. To solve it, I had to move the actual definition of Foo out of the class declaration as such:

class C : public I{
    void Foo();
};

C::Foo(){
   //bar
}

I'm no C++ guru so I can't explain why this is more correct but it solved the problem for me.




I got this error in the following scenario

Consider a case where you have defined the implementation of member functions of a class in the header file itself. This header file is an exported header (in other words, it might be copied to some common/include directly in your codebase). Now you have decided to separate the implementation of the member functions to to .cpp file. After you separated/moved the implementation to .cpp, the header file now has just the prototypes of the member functions inside the class. After the above changes, if you build your codebase you may get the "undefined reference to 'vtable..." error.

To fix this, before building, make sure you delete the header file (to which you made changes) in common/include directory. Also make sure you change your makefile to accomodate/add the new .o file that is built from the new .cpp file you just created. When you do these steps the compiler/linker will no longer complain.




There are a lot of possibilities mentioned for causing this error, and I'm sure many of them do cause the error. In my case, there was another definition of the same class, due to a duplication of the source file. This file was compiled, but not linked, so the linker was complaining about being unable to find it.

To summarize, I would say that if you've stared at the class long enough and can't see what possible syntax problem could be causing it, look for build issues like a missing file or a duplicated file.




In my case I'm using Qt and had defined a QObject subclass in a foo.cpp (not .h) file. The fix was to add #include "foo.moc" at the end of foo.cpp.




I got this error when I added a second class to an existing source/header pair. Two class headers in the same .h file, and function definitions for two classes in the same .cpp file.

I've done this successfully before, with classes that are meant to work closely together, but apparently something didn't like me this time. Still don't know what, but splitting them into one class per compilation unit fixed it right up.


The failed attempt:

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

Again, adding a new source/header pair and cutting/pasting the IconWithData class verbatim into there "just worked".




I got this error just because the name of a constructor argument differed in the header file and in the implementation file. The constructor signature is

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

and what I wrote in the implementation started with

PointSet (const PointSet & pest, Parent * parent)

thus I accidentaly replaced "pset" with "pest". The compiler was complaining about this one and two other constructors in which there was no error at all. I'm using g++ version 4.9.1 under Ubuntu. And defining a virtual destructor in this derived class made no difference (it is defined in the base class). I would have never found this bug if I didn't paste the constructors' bodies in the header file, thus defining them in-class.




Related


Tags

c++   gcc   g++