【问题标题】:GCC C++ Linker errors: Undefined reference to 'vtable for XXX', Undefined reference to 'ClassName::ClassName()'GCC C++ 链接器错误:未定义对 'vtable for XXX' 的引用,未定义对 'ClassName::ClassName()' 的引用
【发布时间】:2010-11-08 21:07:08
【问题描述】:

我正在使用 Eclipse-CDT 在 Ubuntu x64 上设置 C++ 项目。我基本上是在打个招呼,并链接到一个商业 3rd 方库。

我已经包含了头文件,链接到他们的库,但我仍然遇到链接器错误。除了明显的问题之外,这里是否还有一些可能的问题(例如,我 99% 确定我正在链接到正确的库)。

  1. 有没有办法确认我链接的静态库是 64 位的?
  2. 有没有办法确认该库具有我期望它具有的类(和方法)?

Eclipse 说:

构建目标:LinkProblem 调用:GCC C++ 链接器 g++ -L/home/notroot/workspace/somelib-3/somelib/target/bin -o"LinkProblem" ./src/LinkProblem.o -lsomelib1 -lpthread -lsomelib2 -lsomelib3 ./src/LinkProblem.o:在函数“main”中: /home/notroot/workspace/LinkProblem/Debug/../src/LinkProblem.cpp:17:未定义对“SomeClass::close()”的引用 ./src/LinkProblem.o:在函数“SomeOtherClass”中: /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:148:未定义对“SomeClass::SomeClass()”的引用 /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:148:未定义对“用于 SomeOtherClass 的 vtable”的引用 /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:151:未定义对“SomeClass::~SomeClass()”的引用 ./src/LinkProblem.o:在函数“~SomeOtherClass”中: /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:140:未定义对“用于 SomeOtherClass 的 vtable”的引用 /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:140:未定义对“SomeClass::~SomeClass()”的引用 /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:140:未定义对“SomeClass::~SomeClass()”的引用 collect2: ld 返回 1 个退出状态 make: *** [LinkProblem] 错误 1

【问题讨论】:

  • 第三方库是 64 位的吗?
  • 是的,它是 64 位的。不过,您可能会有所作为。如何确保我的代码/项目是 64 位的?在 Visual Studio 中,我创建了一个 x64 构建配置。
  • 有没有办法确认第三方库是64位的?例如。使用工具或其他工具检查 .a 文件?
  • 它在哪里?谷歌显示在 /usr/lib64 中有一个半约定
  • 第三方lib文件在这里:/home/notroot/workspace/somelib-3/somelib/target/bin

标签: c++ linker g++ eclipse-cdt


【解决方案1】:

这个链接器错误通常(根据我的经验)意味着您已经用声明覆盖了子类中的虚函数,但没有给出该方法的定义。例如:

class Base
{
    virtual void f() = 0;
}
class Derived : public Base
{
    void f();
}

但是你还没有给出 f 的定义。使用该类时,会出现链接器错误。就像正常的链接器错误一样,这是因为编译器知道您在说什么,但链接器找不到定义。只是有一个很难理解的消息。

【讨论】:

  • 谢谢。我找了 2 个小时都没找到解决办法。
  • 正是我遇到的问题。谢谢你节省了我的时间和精力。
  • 有趣的是,就我而言,它只发生在“纯虚拟”中!该错误消息确实具有误导性。
  • 这是我的问题。忘记设置为 0!
【解决方案2】:

假设这些方法位于其中一个库中,这看起来像是一个排序问题。

将库链接到可执行文件时,它们按照声明的顺序完成。
此外,链接器将仅采用解决当前未解决的依赖项所需的方法/功能。如果随后的库随后使用对象最初不需要的方法/函数,您将缺少依赖项。

它是如何工作的:

  • 获取所有目标文件并将它们组合成一个可执行文件
  • 解决目标文件之间的任何依赖关系。
  • 按顺序排列每个库:
    • 检查未解析的依赖关系并查看 lib 是否解析它们。
    • 如果是这样,将所需部分加载到可执行文件中。

例子:

对象需要:

  • 打开
  • 关闭
  • 批量读取
  • 批量写入

Lib 1 提供:

  • 打开
  • 关闭
  • 阅读

Lib 2 提供

  • BatchRead(但使用 lib1:read)
  • BatchWrite(但使用 lib1:write)

如果这样链接:

gcc -o plop plop.o -l1 -l2

那么链接器将无法解析读写符号。

但如果我像这样链接应用程序:

gcc -o plop plop.o -l2 -l1

然后它将正确链接。由于 l2 解决了 BatchRead 和 BatchWrite 依赖项,但还添加了两个新的依赖项(读取和写入)。当我们与 l1 链接时,所有四个依赖项都被解析。

【讨论】:

  • 你指的是G++命令行中lib文件的顺序吗?
  • 是的。 :-)
  • 我注意到您的示例使用“gcc”,而我的问题使用“g++”,我应该使用“gcc”吗?
  • 不使用你使用的东西。如果你的代码包含 C++ 的东西,你需要使用 g++ 来获取正确的标准库。
  • 这对我很有帮助!我的 groupproject 突然停止从我的一个库中接受新的 cpp 文件,这完全是关于未定义的引用,然后我切换了位置,它就像一个魅力。说真的,在某些页面上应该有关于这个问题的更具体的文章。非常感谢马丁!
【解决方案3】:

当您更改一个类以使其现在继承自 QObject(即它现在可以使用信号/插槽)时,Qt C++ 将显示此错误。运行 qmake -r 将调用 moc 并修复此问题。

如果您通过某种版本控制与其他人合作,您将需要对您的 .pro 文件进行一些更改(即添加/删除空白行)。当其他人得到您的更改并运行 make 时,make 将看到 .pro 文件已更改并自动运行 qmake。这将使您的队友免于重复您的挫败感。

【讨论】:

  • 谢谢!没有线索很难找到!
  • 另外,如果您忘记将类添加到 *.pro 文件的 HEADER 部分,您将收到相同的错误。类的标题必须是 HEADER,moc 才能获取 Q_OBJECT。
【解决方案4】:

对我来说,问题变得非常模糊。我的班级看起来像这样:

//-----------------------------------------
// libbase.h
class base {
public:
   base() { }
   virtual ~base() { }

   virtual int foo() { return 0; }
};
//-----------------------------------------

//-----------------------------------------
// libbase.cpp
#include "libbase.h"
//-----------------------------------------

//-----------------------------------------
// main.h
class derived : public base {
public:
    virtual int foo() ;
};
//-----------------------------------------

//-----------------------------------------
// main.cpp
int main () {
    derived d;
}
//-----------------------------------------

问题出在链接器中。我的头文件放在某个库中,但所有虚函数在类声明中都被声明为“内联”。由于(还)没有使用虚拟函数的代码,编译器或链接器忽略了将实际函数体放置到位。它也未能创建 vtable。

在我从这个类派生的主代码中,链接器试图将我的类连接到基类和他的 vtable。但是 vtable 已被丢弃。

解决方案是在类声明之外声明至少一个虚函数体,如下所示:

//-----------------------------------------
// libbase.h
class base {
public:
   base() { }
   virtual ~base() ;   //-- No longer declared 'inline'

   virtual int foo() { return 0; }
};
//-----------------------------------------

//-----------------------------------------
// libbase.cpp
#include "libbase.h"
base::~base() 
{
}
//-----------------------------------------

【讨论】:

  • 对我来说是子类和它的虚函数
  • 你错过了类定义末尾的分号:)
【解决方案5】:

关于 Qt4 的问题,我无法使用上面提到的 qmake moc 选项。但这无论如何都不是问题。我在类定义中有以下代码:

class ScreenWidget : public QGLWidget
{
   Q_OBJECT        // must include this if you use Qt signals/slots
...
};

我不得不删除“Q_OBJECT”行,因为我没有定义信号或槽。

【讨论】:

  • 谢谢!使用 g++ 和 cmake 时遇到了这个问题,代码在工作室中编译得很好。
【解决方案6】:

我收到此错误消息。问题是我在头文件中声明了一个虚析构函数,但是虚函数体实际上并没有实现。

【讨论】:

    【解决方案7】:

    当我们在基类中简单地声明一个没有任何定义的虚函数时也会出现这个错误。

    例如:

    class Base
    {
        virtual void method1(); // throws undefined reference error.
    
    }
    

    将上面的声明改成下面的,就可以正常工作了。

    class Base
    {
        virtual void method1()
        {
        }
    }
    

    【讨论】:

    • 这真的对我有用!你能解释一下为什么会这样吗?我见过很多在声明虚函数时不使用花括号的类。
    • @stalin 如果您声明 if 没有大括号,这意味着您将在其他地方实现它(通常在 .cpp 文件中)。
    【解决方案8】:

    在我的情况下,当我忘记在我的纯虚拟类中的一个函数上添加 =0 时,问题就出现了。添加 =0 时已修复。与上面的 Frank 相同。

    class ISettings
    {
    public: 
        virtual ~ISettings() {};
        virtual void OKFunction() =0;
        virtual void ProblemFunction(); // missing =0   
    };
    
    class Settings : ISettings
    {
        virtual ~Settings() {};
        void OKFunction();
        void ProblemFunction(); 
    };
    
    void Settings::OKFunction()
    {
        //stuff
    }
    
    void Settings::ProblemFunction()
    {
        //stuff
    }
    

    【讨论】:

      【解决方案9】:

      我现在也偶然发现了这个问题。该应用程序定义了一个纯虚拟接口类,并且通过共享库提供的用户定义类应该实现该接口。链接应用程序时,链接器抱怨共享库不会为基类提供 vtable 和 type_info,也无法在其他任何地方找到它们。 结果我只是忘记将接口的方法之一设为纯虚拟(即在声明末尾省略了“= 0”。非常简陋,如果您无法将链接器诊断连接到根本原因。

      【讨论】:

        【解决方案10】:

        我在尝试使用 Qt 之类的“hello world”时收到此错误消息。通过正确运行 qt moc(元对象编译器)并正确编译和包含这些 moc 生成的文件,问题就解决了。

        【讨论】:

          【解决方案11】:

          如果你有一个带有纯虚函数的基类,请确保你的基类构造函数和析构函数有主体,否则链接器会失败。

          【讨论】:

          • 其实跟构造函数或析构函数无关。没有这些会给你一个一般的链接器失败。您必须缺少虚拟方法才能在 vtable 上获取链接器错误。
          【解决方案12】:

          我把这个留给未来的访客:

          如果您在创建Exception 对象时收到错误消息,那么其原因可能是缺少what() 虚函数的定义。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-12-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-02-03
            • 1970-01-01
            相关资源
            最近更新 更多