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

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

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

      virtual ~CDasherModule()
      { }
      
      上有一个条目:

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

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

      virtual ~CDasherModule()
      { }
      

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


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

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


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

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

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


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

      为了体现其价值,忘记虚拟析构函数上的实体会生成以下结果:

      对“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提供定义,并将其保持为虚拟函数。 (希望它能起作用,因为我没试过这个)

    • 对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
      (经过测试后,该系统工作正常)
    • 在Clas中提供函数B的定义
      virtual int foo(int x) = 0;
      
      #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
      )