代码之家  ›  专栏  ›  技术社区  ›  waterlooalex

GCC C++链接器错误:未定义引用“xxx的VTABLE”,未定义的“CordNe::Calm NAMEL()”

  •  70
  • waterlooalex  · 技术社区  · 15 年前

    我在Ubuntu X64上建立了一个C++项目,使用Eclipse CDT。我基本上是在做一个“你好”的世界,并链接到一个商业第三方图书馆。

    我已经包含了头文件,链接到了它们的库,但是仍然会得到链接器错误。这里是否有一些明显的问题以外的其他问题(例如,我99%确信我链接到了正确的库)。

    1. 有没有办法确认我链接的静态库是64位的?
    2. 有没有一种方法可以确认库中有我期望它拥有的类(和方法)?

    伊柯丽斯说:

    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 回复  |  直到 6 年前
        1
  •  72
  •   Flow Matt McDonald    8 年前

    假设这些方法在libs中,看起来像是一个排序问题。

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

    它是如何工作的:

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

    例子:

    对象需要:

    • 正常开放
    • 关闭
    • 批读
    • 批写

    LIB 1提供:

    • 正常开放
    • 关闭
    • 阅读

    LIB 2提供

    • batchread(但使用lib1:read)
    • 批写(但使用lib1:write)

    如果链接如下:

    GCC-O plop plop.O-l1-l2

    然后链接器将无法解析读写符号。

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

    GCC-O plop plop.O-l2-l1

    然后它将正确链接。当l2解析batchread和batchwrite依赖项时,还会添加两个新的依赖项(读和写)。当我们与l1连接时,接下来所有四个依赖项都被解析。

        2
  •  167
  •   mgiuca    14 年前

    这个链接器错误通常(在我的经验中)意味着您已经用声明重写了子类中的虚函数,但还没有为该方法提供定义。例如:

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

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

        3
  •  52
  •   Rick Smith Robert Truitt    9 年前

    Qt C++将在更改类时显示此错误,使得它现在从QObjo继承(即现在它可以使用信号/时隙)。运行qmake-r将调用moc并解决此问题。

    如果您通过某种版本控制与其他人合作,您将希望对.pro文件进行一些更改(即添加/删除空行)。当其他人获得您的更改并运行make时,make将看到.pro文件已更改并自动运行qmake。这样可以避免队友重复你的沮丧情绪。

        4
  •  15
  •   Phil Hord    6 年前

    对我来说,这个问题其实很难解。我的课看起来像这样:

    //-----------------------------------------
    // 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() 
    {
    }
    //-----------------------------------------
    
        5
  •  9
  •   mschachter    13 年前

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

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

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

        6
  •  8
  •   lukeinchina    13 年前

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

        7
  •  5
  •   Lundin    11 年前

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

    例如:

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

    把上面的申报改成下面的申报,就可以了。

    class Base
    {
        virtual void method1()
        {
        }
    }
    
        8
  •  4
  •   Lars Persson    11 年前

    在我的例子中,当我忘记在纯虚拟类的一个函数上添加=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
    }
    
        9
  •  1
  •   frank    12 年前

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

        10
  •  0
  •   awallin    14 年前

    我在用qt尝试“hello world”时收到了这个错误消息。通过正确运行qt moc(元对象编译器)和编译+包括这些moc生成的文件,问题就消失了。

        11
  •  0
  •   sumeet    10 年前

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

        12
  •  0
  •   Mostafa Talebi    8 年前

    我把这个给未来的游客:

    如果在创建 Exception 对象,那么其原因可能是缺少 what() 虚拟功能。