提问人:Thomas 提问时间:4/1/2010 最后编辑:iammilindThomas 更新时间:12/11/2020 访问量:45443
Qt Linker 错误:“对 vtable 的未定义引用”[重复]
Qt Linker Error: "undefined reference to vtable" [duplicate]
问:
这是我的标题:
#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
答:
从经验来看:通常 qmake && make clean && make 会有所帮助。 我个人认为,有时更改发现/缓存效果/我不知道 xxxxx 的任何东西。我不能说为什么,但这是我遇到这种错误时做的第一件事。
顺便说一句。> Recive <有一个错别字
您忘记在构造函数中调用 QObject 构造函数(在初始值设定项列表中)。(虽然它不能解决错误)
评论
信号不能有实现(这将由Qt生成)。从 .cpp 文件中删除实现。这可能会解决您的问题。reciveMessage
我看到的另一件事是:由于该类继承自 QObject,因此它必须具有虚拟析构函数以避免在销毁过程中出现问题。必须对从其他类继承的所有类执行此操作。BarelySocket
评论
在我为测试某些东西而创建的一个小“main.cpp”文件中创建了一个小类后,我遇到了这个错误。
经过一个小时左右的处理,我终于将该类从 main.cpp 中移出并移动到一个独立的 hpp 文件中,更新了 .pro(项目)文件,然后项目构建得很好。这可能不是这里的问题,但我认为无论如何它都是有用的信息。
评论
每当向 Q_OBJECT 宏添加新调用时,都需要再次运行 qmake。您所指的 vtables 问题与此直接相关。
只需运行 qmake,假设您的代码中没有其他问题,您应该就可以开始了。
评论
make
qmake
当您从 QOBject 派生类(并使用 Q_OBJECT 宏)时,不要忘记专门定义和创建构造函数和析构函数类。仅仅使用编译器默认构造函数/析构函数是不够的。关于清理/运行 qmake(以及清除 moc_ 文件)的建议仍然适用。 这解决了我的类似问题。
对我来说,我从构建日志中注意到 moc 没有被调用。Clean All 没有帮助。所以我删除了 .pro.user,重新启动了 IDE,它成功了。
评论
grep Class Project.user
我已经看到了很多解决问题的方法,但没有解释为什么会发生这种情况,所以就这样吧。
当编译器看到一个具有虚函数(直接声明或继承)的类时,它必须为该类生成一个 vtable。由于类通常在标头中定义(因此出现在多个翻译单元中),因此问题在于将 vtable 放在哪里。
通常,可以通过在定义类的每个 TU* 中生成 vtable 来解决该问题,然后让链接器消除重复项。由于 ODR 要求每次出现的类定义都相同**,因此这是安全的。但是,它也会减慢编译速度,使对象文件膨胀,并要求链接器执行更多工作。
因此,作为优化,编译器将在可能的情况下选择特定的 TU 来放入 vtable。在常见的 C++ ABI*** 中,此 TU 是实现类的关键函数的 TU,其中关键函数是在类中声明但未定义的第一个虚拟成员函数。
对于 Qt 类,它们通常以 Q_OBJECT 宏开头,并且该宏包含声明
virtual const QMetaObject *metaObject() const;
由于它是宏中的第一个虚函数,因此通常是类的第一个虚函数,因此也是其关键函数。因此,编译器不会在大多数 TU 中发出 vtable,只会发出实现 .此函数的实现是在处理标头时自动编写的。因此,您需要处理标头以生成新的 .cpp 文件,然后在编译中包含 .cpp 文件。metaObject
moc
moc
因此,当您有一个定义 -derived 类的新标头时,您需要重新运行,以便它更新您的生成文件以在新标头上运行并编译生成的 .cpp 文件。QObject
qmake
moc
* TU:翻译单元。它是 C 和 C++ 中的一个艺术术语,指的是单个源文件以及从中传递包含的所有头文件。基本上,编译器在处理单个源文件时看到的内容。
** ODR:一条定义规则。C++ 标准中的一组规则,用于定义在不同的翻译单元中多次定义事物(函数、类等)时会发生什么。
ABI:应用程序二进制接口。对编译时代码组织方式的描述,这是将目标文件链接在一起所必需的。通用 C++ ABI 是 Linux 编译器通常遵循的规范,以便它们可以互操作。
评论
set(CMAKE_AUTOMOC ON)
qmake
cmake
moc
moc
我找到了您可能会看到这种情况的另一个原因 - 因为解析您的类文件,如果您以非标准方式修改它们,您可能会收到此错误。就我而言,我有一个继承自 QDialog 的自定义对话框,但我只希望在为 Linux 而不是 Windows 或 OSX 构建时编译和运行它。我只是把类放出来,所以它没有编译,但在 Linux 中,即使被定义了,它也被抛弃了.qmake
#ifdef __linux__
__linux__
qmake
我为这个错误时间而苦苦挣扎。通过将 .cpp 和 .h 文件放在单独的文件夹中来解决它 (!!) 。 然后在 .pro 文件中添加了文件夹: INCLUDEPATH += $${_PRO_FILE_PWD_}/../MyClasses/CMyClassWidget
然后添加 .cpp 和 .h 文件。 终于起作用了。
评论
qmake
moc