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