对vtable的未定义引用 当我构建我的C++程序时,我得到了错误信息

对vtable的未定义引用 当我构建我的C++程序时,我得到了错误信息,c++,gcc,g++,C++,Gcc,G++,对“vtable”的未定义引用 这个问题的原因是什么?我怎么修理它 碰巧我得到了以下代码的错误(所讨论的类是CGameModule),我一辈子都无法理解问题是什么。起初,我认为这与忘记给一个虚拟的身体赋予功能有关,但据我所知,一切都在这里。继承链有点长,但下面是相关的源代码。我不确定我还应该提供什么信息 注意:构造函数似乎是发生此错误的地方 我的代码: class CGameModule : public CDasherModule { public: CGameModule(Dashe

对“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;
};
  • 您确定
    CDasherComponent
    具有析构函数的主体吗?它肯定不在这里-问题是它是否在.cc文件中
  • 从样式的角度来看,
    CDasherModule
    应该明确定义其析构函数
    virtual
  • 看起来,
    CGameModule
    在末尾有一个额外的
    }
    (在
    };//类的后面)
  • CGameModule
    是否与定义
    CDasherModule
    CDasherComponent
    的库相链接
上有一个条目:

解决方案是确保定义所有非纯虚拟方法。请注意,必须定义析构函数,即使它被声明为纯虚拟[class.dtor]/7

因此,您需要提供虚拟析构函数的定义:

virtual ~CDasherModule()
{ }

所以,我发现了这个问题,这是一个糟糕的逻辑和不完全熟悉汽车制造/自动工具世界的组合。我将正确的文件添加到Makefile.am模板中,但我不确定构建过程中的哪个步骤实际创建了Makefile本身。所以,我是用一个旧的makefile编译的,它根本不知道我的新文件


感谢您的回复和GCC常见问题的链接。我一定会读到,为了避免这个问题出于真正的原因而发生。

不管怎样,忘记虚拟析构函数上的实体会产生以下结果:

对“CYourClass的vtable”的未定义引用


我添加了一个注释,因为错误消息具有欺骗性。(这是在gcc版本4.6.3中出现的。)

由于以下情况,可能会出现未定义的vtable引用。试试这个:

A类包括:

virtual void functionA(parameters)=0; 
virtual void functionB(parameters);
B类包括:

virtual void functionA(parameters)=0; 
virtual void functionB(parameters);
  • 上述函数的定义
  • 上述函数的定义b
  • 类C包含:现在您正在编写一个类C,在其中您将从类a派生它

    现在,如果您尝试编译,您将得到对C类vtable的未定义引用作为错误

    原因:

    function
    定义为纯虚拟,其定义在B类中提供。
    functionB
    被定义为虚拟的(不是纯虚拟的),因此它试图在类A中找到它的定义,但您在类B中提供了它的定义

    解决方案:

  • 使函数B成为纯虚拟函数(如果您有这样的需求)
    虚空函数b(参数)=0
    (经过测试后,该系统工作正常)
  • 为类A中的函数B提供定义,并将其保持为虚拟函数。 (希望它能起作用,因为我没试过这个)

  • 我只是因为.cpp文件不在makefile中而出现这个错误


    通常,如果您忘记编译或链接到包含定义的特定对象文件,您将遇到此错误。

    如果所有其他操作都失败,请查找重复。在我读到另一篇文章中的引用之前,我一直被对构造函数和析构函数的明确的初始引用误导。这是任何未解决的方法。在我的例子中,我认为我已经将使用
    char*xml
    作为参数的声明替换为使用不必要的麻烦
    const char*xml
    的声明,但是相反,我创建了一个新的声明,并保留了另一个声明。

    不是交叉发布,而是。如果你处理的是继承问题,那么第二次谷歌点击就是我错过的,即所有虚拟方法都应该被定义

    例如:

    virtual void fooBar() = 0;
    

    有关详细信息,请参见answare。刚刚意识到上面已经提到了它,但它可能会帮助某些人。

    如果您正在使用Qt,请尝试重新运行qmake。如果此错误在小部件的类中,qmake可能没有注意到应该重新生成ui类vtable。这就为我解决了这个问题。

    < p>在你定义了一个对象的虚拟函数的定义时,GNU C++编译器必须在哪里放置“代码”> vtab>代码(例如,一些对象的虚拟函数定义是在.CPP文件中的,其他的是在另一个.CPP文件中,等等)。p> 编译器选择将
    vtable
    放在定义第一个声明的虚拟函数的相同位置

    现在,如果您出于某种原因忘记为对象中声明的第一个虚拟函数提供定义(或者错误地忘记在链接阶段添加编译后的对象),您将得到此错误


    作为一个副作用,请注意,只有对于这个特定的虚拟函数,您不会得到传统的链接器错误,就像您缺少函数foo一样。

    我刚刚遇到了这个错误的另一个原因,您可以检查一下

    基类将纯虚函数定义为:

    virtual int foo(int x = 0);
    
    而这个子类

    int foo(int x) override;
    
    问题在于输入错误,
    “=0”
    应该在括号外:

    virtual int foo(int x) = 0;
    

    因此,如果你向下滚动这么远,你可能找不到答案-这是需要检查的其他内容。

    这里有很多关于各种答案的推测。下面我将给出一个相当小的代码来重现这个错误,并解释它发生的原因

    M
    #pragma once
    
    class IBase {
        public:
            virtual void action() = 0;
    };
    
    #pragma once
    
    #include "IBase.hpp"
    
    class Derived : public IBase {
        public:
            Derived(int a);
            void action() override;
    };
    
    #include "Derived.hpp"
    Derived::Derived(int a) { }
    void Derived::action() {}
    
    #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;
    }
    
    g++ -std=c++11 -o a.out myclass.cpp Derived.cpp
    
    ~/.../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
    
    add_executable(myclass src/myclass.cpp src/Derived.cpp)
    add_dependencies(myclass theseus_myclass_cpp)
    target_link_libraries(myclass ${catkin_LIBRARIES})
    
    #ifdef something
    
    class Foo
    {
    public:
        virtual void StartFooing();
    };
    
    #include "Foo.hpp"
    
    void Foo::StartFooing(){ //fooing }
    
    g++ Foo.cpp -c
    
    #include "Foo.hpp"
    
    int main()
    {
        Foo foo;
    }
    
    g++ main.cpp -o main
    
    virtual ~A() = default;
    
    virtual ~A() {}
    
    virtual ~A();
    
    A::~A() {}
    
    # CMakeLists.txt
    cmake_minimum_required(VERSION 3.12)
    project (space_engine)
    add_library (CelestialBody SHARED CelestialBody.cpp)
    add_library (Planet SHARED Planet.cpp)
    target_include_directories (CelestialBody PRIVATE ${CMAKE_CURRENT_LIST_DIR})  
    target_include_directories (Planet PRIVATE ${CMAKE_CURRENT_LIST_DIR})    
    target_link_libraries (Planet PUBLIC CelestialBody)
    
    # hardened linker flags to catch undefined symbols
    target_link_options(Planet 
        PRIVATE 
        -Wl,--as-needed
        -Wl,--no-undefined
    )