Qt链接器错误:“未定义的引用vtable”

这是我的标题:

#ifndef BARELYSOCKET_H #define BARELYSOCKET_H #include <QObject> //! The First Draw of the BarelySocket! class BarelySocket: public QObject { Q_OBJECT public: BarelySocket(); public slots: void sendMessage(Message aMessage); signals: void reciveMessage(Message aMessage); private: // QVector<Message> reciveMessages; }; #endif // BARELYSOCKET_H 

这是我的class级:

 #include <QTGui> #include <QObject> #include "type.h" #include "client.h" #include "server.h" #include "barelysocket.h" BarelySocket::BarelySocket() { //this->reciveMessages.clear(); qDebug("BarelySocket::BarelySocket()"); } void BarelySocket::sendMessage(Message aMessage) { } void BarelySocket::reciveMessage(Message aMessage) { } 

我收到一个链接器错误:

 undefined reference to 'vtable for BarelySocket' 
  • 这意味着我有一个虚拟的方法没有实现。 但是class上没有虚拟的方法。
  • 我注意到向量认为这是原因,但错误没有消失。
  • Message是一个复杂的struct ,但即使使用int代替也不能解决问题。

任何时候你添加一个新的调用到Q_OBJECTmacros,你需要再次运行qmake。 你提到的vtables问题直接与此有关。

只要运行qmake,你应该很好地假设你的代码中没有其他问题。

我已经看到很多方法来解决这个问题,但没有解释为什么会发生这种情况,所以在这里。

当编译器看到具有虚函数的类(直接声明或inheritance)时,它必须为该类生成一个vtable。 由于类通常在头文件中定义(因此出现在多个翻译单元中),问题在于放置vtable的位置。

一般来说,问题可以通过在定义类的每个TU中生成vtable来解决,然后让链接器消除重复。 由于ODR在每个事件中都要求类定义是相同的,所以这是安全的。 但是,这也会减慢编译速度,扩大目标文件,并且要求链接器做更多的工作。

因此,作为一种优化,编译器将尽可能select一个特定的TU来放置vtable。在普通的C ++ ABI中,这个TU是类的关键函数被实现的地方,其中关键函数是在类中声明的第一个虚拟成员函数,但没有定义。

在Qt类的情况下,它们通常以Q_OBJECTmacros开始,而这个macros包含声明

 virtual const QMetaObject *metaObject() const; 

它是macros观中第一个虚拟function,它通常将是该类的第一个虚拟function,因此也是其关键function。 因此,编译器不会在大多数TU中发出vtable,而只是实现metaObject 。 而这个函数的实现是由moc在处理头部时自动编写的。 因此,您需要让moc处理您的头文件以生成新的.cpp文件,然后将.cpp文件包含在您的编译中。

所以当你有一个新的头文件来定义一个QObject派生类的时候,你需要重新运行qmake这样它就可以更新你的makefile来在新的头文件上运行moc并编译生成的.cpp文件。

在我创build一个小的“main.cpp”文件里面创build了一个小类来testing一些东西之后,我遇到了这个错误。

经过一个小时左右的时间,我终于把这个类从main.cpp中移出来,放到一个独立的hpp文件中,更新了.pro(project)文件,然后项目就完成了。 这可能不是问题,但我认为这将是有用的信息。

从经验:通常qmake &&使干净&&使帮助。 我个人认为,有时候改变发现/caching效果/不pipe我不知道xxxxx。 我不能说为什么,但这是我遇到这种错误时所做的第一件事。

顺便说一句。 在recive <有一个错字

您忘记调用构造函数中的QObject构造函数(在初始化程序列表中)。 (虽然没有解决错误)

对我来说,我从构build日志中注意到moc没有被调用。 全部清理没有帮助。 所以我删除了.pro.user,重新启动了IDE,它的确有窍门。

信号不能有执行(这将由Qt生成)。 从.cpp文件中删除reciveMessage实现。 这可能会解决你的问题。

另一件我见过的:由于BarelySocket类inheritance自QObject,它必须有一个虚拟的析构函数来避免销毁时的问题。 对于从其他类inheritance的所有类,这必须完成。

从Qobject派生类(并使用Q_OBJECTmacros)时,不要忘记专门定义和创build构造函数和析构函数类。 使用编译器的默认构造函数/析构函数是不够的。 关于清理/运行qmake(和清理你的moc_文件)的build议仍然适用。 这固定我的类似的问题。

我与这个错误小时挣扎。 通过将.cpp和.h文件放在一个单独的文件夹(!!)解决它。 然后在.pro文件中添加该文件夹:INCLUDEPATH + = $$ {_ PRO_FILE_PWD _} /../ MyClasses / CMyClassWidget

然后添加.cpp和.h文件。 最后工作。

我发现另一个原因,你可能会看到这一点 – 因为qmakeparsing你的类文件,如果你以非标准的方式修改它们,你可能会得到这个错误。 在我的情况下,我有一个从QDialoginheritance的自定义对话框,但我只想在为Linux构build而不是Windows或OSX时编译和运行。 我只是#ifdef __linux__这个类,所以它没有编译,但是在Linux中,尽pipe__linux__被定义了,但它却抛弃了qmake