Undefined reference to vtable

2019-07-28 01:28发布

问题:

When building my C++ program, I'm getting the error message

undefined reference to 'vtable...

What is the cause of this problem? How do I fix it?


It so happens that I'm getting the 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

回答1:

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.



回答2:

For what it is worth, forgetting a body on a virtual destructor generates the following:

undefined reference to `vtable for CYourClass'.

I am adding a note because the error message is deceptive. (This was with gcc version 4.6.3.)



回答3:

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.



回答4:

If you are using Qt, try rerunning qmake. If this error is in the widget's class, qmake might have failed to notice that the ui class vtable should be regenerated. This fixed the issue for me.



回答5:

Undefined reference to vtable may occur due to the following situation also. Just try this:

Class A Contains:

virtual void functionA(parameters)=0; 
virtual void functionB(parameters);

Class B Contains:

  1. The definition for the above functionA.
  2. The definition for the above functionB.

Class C Contains: Now you're writing a Class C in which you are going to derive it from Class A.

Now if you try to compile you will get Undefined reference to vtable for Class C as error.

Reason:

functionA is defined as pure virtual and its definition is provided in Class B. functionB is defined as virtual (NOT PURE VIRTUAL) so it tries to find its definition in Class A itself but you provided its definition in Class B.

Solution:

  1. Make function B as pure virtual (if you have requirement like that) virtual void functionB(parameters) =0; (This works it is Tested)
  2. Provide Definition for functionB in Class A itself keeping it as virtual . (Hope it works as I didn't try this)


回答6:

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



回答7:

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.



回答8:

There is lot of speculation going on in various answers here. I'll below give a fairly minimal code that reproduces this error and explain why it is occuring.

Fairly Minimal Code to Reproduce This Error

IBase.hpp

#pragma once

class IBase {
    public:
        virtual void action() = 0;
};

Derived.hpp

#pragma once

#include "IBase.hpp"

class Derived : public IBase {
    public:
        Derived(int a);
        void action() override;
};

Derived.cpp

#include "Derived.hpp"
Derived::Derived(int a) { }
void Derived::action() {}

myclass.cpp

#include <memory>
#include "Derived.hpp"

class MyClass {

    public:
        MyClass(std::shared_ptr<Derived> newInstance) : instance(newInstance) {

        }

        void doSomething() {
            instance->action();
        }

    private:
        std::shared_ptr<Derived> instance;
};

int main(int argc, char** argv) {
    Derived myInstance(5);
    MyClass c(std::make_shared<Derived>(myInstance));
    c.doSomething();
    return 0;
}

You can compile this using GCC like this:

g++ -std=c++11 -o a.out myclass.cpp Derived.cpp

You can now reproduce the error by removing = 0 in IBase.hpp. I get this error:

~/.../catkin_ws$ g++ -std=c++11 -o /tmp/m.out /tmp/myclass.cpp /tmp/Derived.cpp
/tmp/cclLscB9.o: In function `IBase::IBase(IBase const&)':
myclass.cpp:(.text._ZN5IBaseC2ERKS_[_ZN5IBaseC5ERKS_]+0x13): undefined reference to `vtable for IBase'
/tmp/cc8Smvhm.o: In function `IBase::IBase()':
Derived.cpp:(.text._ZN5IBaseC2Ev[_ZN5IBaseC5Ev]+0xf): undefined reference to `vtable for IBase'
/tmp/cc8Smvhm.o:(.rodata._ZTI7Derived[_ZTI7Derived]+0x10): undefined reference to `typeinfo for IBase'
collect2: error: ld returned 1 exit status

Explanation

Notice that above code does not require any virtual destructors, constructors or any other extra files for compile to be successful (although you should have them).

The way to understand this error is as follows: Linker is looking for constructor of IBase. This it will need it for the constructor of Derived. However as Derived overrides methods from IBase, it has vtable attached to it that will reference IBase. When linker says "undefined reference to vtable for IBase" it basically means that Derived has vtable reference to IBase but it can't find any compiled object code of IBase to look up to. So the bottom line is that class IBase has declarations without implementations. This means a method in IBase is declared as virtual but we forgot to mark it as pure virtual OR provide its definition.

Parting Tip

If all else fails then one way to debug this error is to build minimal program that does compile and then keep changing it so it gets to the state you want. In between, keep compiling to see when it starts to fail.

Note on ROS and Catkin build system

If you were compiling above set of classes in ROS using catkin build system then you will need following lines in CMakeLists.txt:

add_executable(myclass src/myclass.cpp src/Derived.cpp)
add_dependencies(myclass theseus_myclass_cpp)
target_link_libraries(myclass ${catkin_LIBRARIES})

The first line basically says that we want to make an executable named myclass and the code to build this can be found files that follows. One of these files should have main(). Notice that you don't have to specify .hpp files anywhere in CMakeLists.txt. Also you don't have to specify Derived.cpp as library.



回答9:

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



回答10:

The GNU C++ compiler has to make a decision where to put the vtable in case you have the definition of the virtual functions of an object spread across multiple compilations units (e.g. some of the objects virtual functions definitions are in a .cpp file others in another .cpp file, and so on).

The compiler chooses to put the vtable in the same place as where the first declared virtual function is defined.

Now if you for some reason forgot to provide a definition for that first virtual function declared in the object (or mistakenly forgot to add the compiled object at linking phase), you will get this error.

As a side effect, please note that only for this particular virtual function you won't get the traditional linker error like you are missing function foo.



回答11:

Not to cross post but. If you are dealing with inheritance the second google hit was what I had missed, ie. all virtual methods should be defined.

Such as:

virtual void fooBar() = 0;

See answare C++ Undefined Reference to vtable and inheritance for details. Just realized it's already mentioned above, but heck it might help someone.



回答12:

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
{

}


回答13:

  • 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?


回答14:

Perhaps missing the virtual destructor is contributing factor?

virtual ~CDasherModule(){};


回答15:

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() {
}


回答16:

Not perhaps. Definitely ~CDasherModule() {} is missing.



回答17:

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.



回答18:

So I was using Qt with Windows XP and MinGW compiler and this thing was driving me crazy.

Basically the moc_xxx.cpp was generated empty even when I was added

Q_OBJECT

Deleting everything making functions virtual, explicit and whatever you guess doesn't worked. Finally I started removing line by line and it turned out that I had

#ifdef something

Around the file. Even when the #ifdef was true moc file was not generated.

So removing all #ifdefs fixed the problem.

This thing was not happening with Windows and VS 2013.



回答19:

If all else fails, look for duplication. I was misdirected by the explicit initial reference to constructors and destructors until I read a reference in another post. It's any unresolved method. In my case, I thought I had replaced the declaration that used char *xml as the parameter with one using the unnecessarily troublesome const char *xml, but instead, I had created a new one and left the other one in place.



回答20:

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.



回答21:

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.



回答22:

I think it's also worth mentioning that you will also get the message when you try to link to object of any class that has at least one virtual method and linker cannot find the file. For example:

Foo.hpp:

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

Foo.cpp:

#include "Foo.hpp"

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

Compiled with:

g++ Foo.cpp -c

And main.cpp:

#include "Foo.hpp"

int main()
{
    Foo foo;
}

Compiled and linked with:

g++ main.cpp -o main

Gives our favourite error:

/tmp/cclKnW0g.o: In function main': main.cpp:(.text+0x1a): undefined reference tovtable for Foo' collect2: error: ld returned 1 exit status

This occure from my undestanding becasue:

  1. Vtable is created per class at compile time

  2. Linker does not have access to vtable that is in Foo.o



回答23:

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.



回答24:

I got this type of error in situations where I was trying to link to an object when I got a make bug that prevented the object being added to the archive.

Say I have libXYZ.a that supposed to have bioseq.o in int but it does not.

I got an error:

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

This is quit different from all of the above. I would call this missing object in the archive problem.



回答25:

It's also possible that you get a message like

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'

if you forget to define a virtual function of a class FakeClass1 when you're trying to link a unit test for another class SomeClass.

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

And

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

In this case I suggest you check out your fake for class1 once again. You'll probably find that you may have forgotten to define a virtual function ForgottenFunc in your fake class.



回答26:

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".



回答27:

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.



标签: c++ gcc g++