GCC C ++链接器错误:未定义引用'vtable for XXX',未定义引用'ClassName :: ClassName()'

时间:2009-07-07 23:03:25

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

我正在使用Eclipse-CDT在Ubuntu x64上设置一个C ++项目。我基本上是在打招呼世界并链接到商业第三方图书馆。

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

  1. 有没有办法确认我链接的静态库是64位?
  2. 有没有办法确认图书馆有我期望的类(和方法)?
  3. Eclipse说:

    Building target: LinkProblem
    Invoking: GCC C++ Linker
    g++ -L/home/notroot/workspace/somelib-3/somelib/target/bin -o"LinkProblem"  ./src/LinkProblem.o   -lsomelib1 -lpthread -lsomelib2 -lsomelib3
    ./src/LinkProblem.o: In function `main':
    /home/notroot/workspace/LinkProblem/Debug/../src/LinkProblem.cpp:17: undefined reference to `SomeClass::close()'
    ./src/LinkProblem.o: In function `SomeOtherClass':
    /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:148: undefined reference to `SomeClass::SomeClass()'
    /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:148: undefined reference to `vtable for SomeOtherClass'
    /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:151: undefined reference to `SomeClass::~SomeClass()'
    ./src/LinkProblem.o: In function `~SomeOtherClass':
    /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:140: undefined reference to `vtable for SomeOtherClass'
    /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:140: undefined reference to `SomeClass::~SomeClass()'
    /home/notroot/workspace/somelib-3/somelib/include/sql/somefile.h:140: undefined reference to `SomeClass::~SomeClass()'
    collect2: ld returned 1 exit status
    make: *** [LinkProblem] Error 1
    

12 个答案:

答案 0 :(得分:168)

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

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

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

答案 1 :(得分:73)

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

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

工作原理:

  • 获取所有目标文件并将它们合并为可执行文件
  • 解析目标文件之间的所有依赖关系。
  • 按顺序为每个库:
    • 检查未解析的依赖项,并查看lib是否解析它们。
    • 如果需要加载部分到可执行文件中。

示例:

对象需要:

  • 打开
  • 关闭
  • BatchRead
  • BatchWrite

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链接时,所有四个依赖关系都会被解析。

答案 2 :(得分:52)

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

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

答案 3 :(得分:15)

对我而言,这个问题非常模糊。我的班级看起来像这样:

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

问题出在链接器中。我的头文件在某个库中进入,但是所有的虚函数都在类声明中声明为'inline'。由于没有使用虚函数的代码(尚未),编译器或链接器忽略了将实际的函数体放在适当的位置。它也无法创建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() 
{
}
//-----------------------------------------

答案 4 :(得分:9)

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

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

我必须删除“Q_OBJECT”行,因为我没有定义信号或插槽。

答案 5 :(得分:8)

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

答案 6 :(得分:5)

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

例如:

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

}

将上述声明更改为以下声明,它将正常工作。

class Base
{
    virtual void method1()
    {
    }
}

答案 7 :(得分:4)

在我的情况下,当我忘记在我的纯虚拟类中的一个函数上添加= 0时出现问题。当添加= 0时,它被修复。和上面的弗兰克一样。

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
}

答案 8 :(得分:1)

我现在偶然发现了这个问题。应用程序定义了一个纯虚拟接口类,并且通过共享库提供的用户定义类应该实现该接口。链接应用程序时,链接器抱怨共享库不会为基类提供vtable和type_info,也不能在其他任何地方找到它们。 原来我只是忘了让接口的方法之一纯虚拟(即在声明结尾处省略了“= 0”。非常基本的,如果你不能将链接器诊断连接到的话,仍然很容易被忽视和令人费解根本原因。

答案 9 :(得分:0)

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

答案 10 :(得分:0)

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

答案 11 :(得分:0)

我把它放在未来的访客中:

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