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

时间:2010-03-31 19:19:17

标签: c++ qt linker-errors vtable qobject

这是我的标题:

#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

这是我的班级:

#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'
  • 这意味着我有一个未实现的虚方法。但那里 我班上没有虚拟方法。
  • 我评论出载体认为它是原因,但是 错误没有消失。
  • Message是一个复杂的struct,但即使使用int也是如此 不解决问题。

9 个答案:

答案 0 :(得分:131)

每次向Q_OBJECT宏添加新调用时,都需要再次运行qmake。您所指的vtable问题与此直接相关。

只需运行qmake,您应该好好假设代码中没有其他问题。

答案 1 :(得分:36)

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

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

通常,可以通过在定义类的每个TU中生成vtable来解决问题,然后让链接器消除重复。由于ODR在每次出现时要求类定义相同,因此这是安全的。但是,它也会降低编译速度,膨胀对象文件,并要求链接器执行更多工作。

因此,作为优化,编译器将尽可能选择特定的TU来放入vtable。在常见的C ++ ABI中,此TU是类的键函数在key中实现,其中key函数是在类中声明但未定义的第一个虚拟成员函数。

对于Qt类,它们通常以Q_OBJECT宏开头,并且此宏包含声明

virtual const QMetaObject *metaObject() const;

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

因此,如果您有一个定义QObject派生类的新标头,则需要重新运行qmake,以便更新您的makefile以在新标头上运行moc并编译生成的.cpp文件。

答案 2 :(得分:13)

我在一个小的“main.cpp”文件中创建了一个小类后,我遇到了这个错误。

经过一个小时左右的训练后,我终于将该课程从main.cpp移到了一个独立的hpp文件中,更新了.pro(项目)文件,然后项目完全正常。这可能不是这里的问题,但我认为无论如何它都是有用的信息。

答案 3 :(得分:10)

从经验来看:经常是qmake&amp;&amp;使干净&amp;&amp;帮助。 我个人认为有时候改变发现/缓存效果/不管怎么说 - 我不知道xxxxx。我不能说为什么,但这是我遇到这种错误时做的第一件事。

顺便说一句。 &gt;输入错误recive&lt;

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

答案 4 :(得分:4)

对我来说,我注意到构建日志中没有调用moc。清洁一切没有帮助。所以我删除了.pro.user,重新启动了IDE并且它完成了这个技巧。

答案 5 :(得分:2)

信号必须没有实现(这将由Qt生成)。从.cpp文件中删除reciveMessage实现。这可以解决您的问题。

我见过的另一件事:由于BarelySocket类继承自QObject,它必须有一个虚拟析构函数,以避免在销毁过程中出现问题。必须对从其他类继承的所有类完成此操作。

答案 6 :(得分:2)

从QOBject派生类(并使用Q_OBJECT宏)时,不要忘记专门定义和创建构造函数和析构函数类。使用编译器默认构造函数/析构函数是不够的。关于清理/运行qmake(以及清除moc_文件)的建议仍然适用。 这解决了我类似的问题。

答案 7 :(得分:1)

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

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

答案 8 :(得分:0)

我找到了另一个原因,您可能会看到这一点 - 因为qmake解析了您的类文件,如果您以非标准方式修改它们,则可能会出现此错误。在我的情况下,我有一个继承自QDialog的自定义对话框,但我只想在为Linux构建时编译和运行,而不是Windows或OSX。我只是#ifdef __linux__课程,所以它没有编译,但在Linux中,即使定义了__linux__,它也会抛弃qmake