Qt Linker 错误:“对 vtable 的未定义引用”[重复]

Qt Linker Error: "undefined reference to vtable" [duplicate]

提问人:Thomas 提问时间:4/1/2010 最后编辑:iammilindThomas 更新时间:12/11/2020 访问量:45443

问:

这是我的标题:

#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'
  • 这意味着我有一个未实现的虚拟方法。但是那里 在我的类中没有虚拟方法。
  • 我注释掉了向量,认为这是原因,但是 错误并没有消失。
  • 这是一个复杂的,但即使使用代替 不解决问题。Messagestructint
C++ Qt 链接器错误 vtable qobject

评论

7赞 Tyler McHenry 4/1/2010
你有没有尝试过从运行开始的干净构建?如果由于某种原因没有处理类的标头,则可能会发生这种情况。qmakemoc
0赞 Thomas 4/8/2010
我正在使用 QT Creator。我将所有 cpp 文件复制到一个新的干净 Projekt 中。我删除了我错误编码的插槽实现。比问题消失了。感谢您的帮助!

答:

11赞 Ronny Brendel 4/1/2010 #1

从经验来看:通常 qmake && make clean && make 会有所帮助。 我个人认为,有时更改发现/缓存效果/我不知道 xxxxx 的任何东西。我不能说为什么,但这是我遇到这种错误时做的第一件事。

顺便说一句。> Recive <有一个错别字

您忘记在构造函数中调用 QObject 构造函数(在初始值设定项列表中)。(虽然它不能解决错误)

评论

5赞 Kaleb Pederson 4/1/2010
当文件已经存在但在运行 qmake 时没有任何Q_OBJECT引用时,这特别有用。然后,QMake 认为它不需要运行 MoC,您最终会遇到 vtable 错误。清洁并不总是必要的,但当进行某些结构更改时。
5赞 chalup 4/1/2010
还要确保 barelysocket.h 位于 pro 文件的 HEADERS 部分中。
0赞 Hitokage 8/12/2022
@chalup 这是我的问题,当使用hpp文件时!谢谢!
3赞 Patrice Bernassola 4/1/2010 #2

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

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

评论

0赞 chalup 4/1/2010
删除 receiveMessage 实现是必要的,但它更会导致“multiply defined symbol”错误。如果基类(在本例中为 QObject)具有虚拟析构函数,则所有派生类中的析构函数都自动为虚拟析构函数。所以这不是问题。
18赞 David 7/13/2010 #3

在我为测试某些东西而创建的一个小“main.cpp”文件中创建了一个小类后,我遇到了这个错误。

经过一个小时左右的处理,我终于将该类从 main.cpp 中移出并移动到一个独立的 hpp 文件中,更新了 .pro(项目)文件,然后项目构建得很好。这可能不是这里的问题,但我认为无论如何它都是有用的信息。

评论

0赞 Roman Kiselev 1/18/2018
我今天犯了同样的错误!也损失了大约一个小时左右......
0赞 Harish Ganesan 1/22/2020
知道为什么会这样吗?今天也发生在我身上。
162赞 Michael 9/6/2010 #4

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

只需运行 qmake,假设您的代码中没有其他问题,您应该就可以开始了。

评论

34赞 Michael Hilbert 7/26/2012
在 QT Creator 中,使用 从 Build 菜单运行 qmake。
2赞 Thomas 8/31/2016
谢谢!从命令行中,仅正常使用也会更新一些与 qmake 相关的东西,但显然还不够。显式运行确实是必需的。makeqmake
0赞 Paul Wintz 2/20/2018
运行 qmake 对我来说还不够,我不得不删除我的构建文件夹然后重新编译。
0赞 yasriady 11/24/2019
这是工作,我只是重新运行了qmake
0赞 Majid 7/4/2021
对我不起作用。我尝试了所有这些,但没有任何效果。当我删除宏时Q_OBJECT我可以成功构建,但我认为这不是一个正确的方法!
2赞 Pete 10/8/2010 #5

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

6赞 lstipakov 11/12/2010 #6

对我来说,我从构建日志中注意到 moc 没有被调用。Clean All 没有帮助。所以我删除了 .pro.user,重新启动了 IDE,它成功了。

评论

0赞 Nulik 12/8/2018
这也正是发生在我身上的事情。这个QtCreator错误是当我添加一个不是QObject父级的类时触发的,但后来手动修复了它。我做到了,但它缺少文件。所以我只是删除了 .user 文件,重建了所有内容,错误就消失了grep Class Project.user
53赞 Sebastian Redl 11/14/2014 #7

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

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

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

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

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

virtual const QMetaObject *metaObject() const;

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

因此,当您有一个定义 -derived 类的新标头时,您需要重新运行,以便它更新您的生成文件以在新标头上运行并编译生成的 .cpp 文件。QObjectqmakemoc

* TU:翻译单元。它是 C 和 C++ 中的一个艺术术语,指的是单个源文件以及从中传递包含的所有头文件。基本上,编译器在处理单个源文件时看到的内容。

** ODR:一条定义规则。C++ 标准中的一组规则,用于定义在不同的翻译单元中多次定义事物(函数、类等)时会发生什么。

ABI:应用程序二进制接口。对编译时代码组织方式的描述,这是将目标文件链接在一起所必需的。通用 C++ ABI 是 Linux 编译器通常遵循的规范,以便它们可以互操作。

评论

7赞 Kyle Strand 11/12/2015
很棒的文章。我使用的是 CMake 而不是 qmake,我经常看到这个错误;理解基本的 C++ vtable 信息并且仍然无法弄清楚出了什么问题,这是非常令人沮丧的。谢谢!
0赞 James Hirschorn 5/31/2016
@Kyle Strand:应该不够吗?我有一个Qt库,每次都必须运行以避免vtable错误。这是否意味着没有按应有的方式运行?set(CMAKE_AUTOMOC ON)qmakecmakemoc
1赞 Kyle Strand 5/31/2016
@JamesHirschorn 你会认为这应该足够了,是的。事实上,似乎每次构建都会重新运行,而不考虑输入文件是否实际更改。我不太确定基本的 CMake 问题是什么。moc
0赞 AlastairG 1/17/2019
我在 CMake 上也有这个问题,是的,我看到 automoc 正在运行,但没有生成文件。如何让 automoc 扫描头文件?
1赞 Sebastian Redl 12/11/2020
@xcski 好主意,添加了一些定义。
0赞 Preston 8/13/2015 #8

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

1赞 Sunny127 1/4/2017 #9

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

然后添加 .cpp 和 .h 文件。 终于起作用了。