C++ Qt链接器错误:";未定义对vtable的引用;

C++ Qt链接器错误:";未定义对vtable的引用;,c++,qt,linker-errors,vtable,qobject,C++,Qt,Linker Errors,Vtable,Qobject,这是我的标题: \ifndef BARELYSOCKET\u H #定义BARELYSOCKET_H #包括 //! BarelySocket的第一次抽签! BarelySocket类:公共QObject { Q_对象 公众: BarelySocket(); 公众时段: 无效发送消息(消息A消息); 信号: 无效接收消息(消息A消息); 私人: //QVector接收消息; }; #endif//BARELYSOCKET_H 这是我的班级: #包括 #包括 #包括“h型” #包括“clien

这是我的标题:

\ifndef BARELYSOCKET\u H
#定义BARELYSOCKET_H
#包括
//! BarelySocket的第一次抽签!
BarelySocket类:公共QObject
{
Q_对象
公众:
BarelySocket();
公众时段:
无效发送消息(消息A消息);
信号:
无效接收消息(消息A消息);
私人:
//QVector接收消息;
};
#endif//BARELYSOCKET_H
这是我的班级:

#包括
#包括
#包括“h型”
#包括“client.h”
#包括“server.h”
#包括“barelysocket.h”
BarelySocket::BarelySocket()
{
//此->receivemessages.clear();
qDebug(“BarelySocket::BarelySocket()”;
}
void BarelySocket::sendMessage(Message aMessage)
{
}
void BarelySocket::reciveMessage(Message aMessage)
{
}
我收到一个链接器错误:

对“用于BarelySocket的vtable”的未定义引用
  • 这意味着我有一个虚拟方法没有实现。但是那里 在我的类中没有虚拟方法
  • 我注释掉了向量,认为这是原因,但是 错误并没有消失
  • 消息
    是一个复杂的
    结构
    ,但即使使用
    int
    也不例外 不要修理东西

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


顺便说一句,在>接收信号处有一个输入错误,不能有一个实现(这将由Qt生成)。从.cpp文件中删除接收消息的实现。这可能会解决你的问题


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

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


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

任何时候向Q_对象宏添加新调用时,都需要再次运行qmake。您所指的vtables问题与此直接相关


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

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

对于我来说,我从构建日志中注意到没有调用moc。把所有的东西都清理干净也没用。因此,我删除了.pro.user,重新启动了IDE,它成功了。

我已经看到了很多解决问题的方法,但没有解释为什么会发生这种情况,下面就是

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

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

因此,作为一种优化,编译器将在可能的情况下选择一个特定的TU来放置vtable。在普通C++中,这个TU是一个在其中实现了键函数的键,其中键函数是在类中声明的第一个虚成员函数,但未定义。 对于Qt类,它们通常以Q_OBJECT宏开始,该宏包含声明

virtual const QMetaObject *metaObject() const;
因为它是宏中的第一个虚函数,所以通常是类的第一个虚函数,因此也是它的关键函数。因此,在大多数TU中,编译器不会发出vtable,只会发出实现
元对象的vtable。该函数的实现是由
moc
在处理报头时自动编写的。因此,您需要让
moc
处理头文件以生成新的.cpp文件,然后将.cpp文件包括在编译中

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

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

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


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

< P>我发现了另一个可能会看到的原因。因为,通过代码类>解析Q> >代码>通过您的类文件进行解析,如果您以非标准方式修改它们,则可能会得到此错误。在我的例子中,我有一个从QDialog,b继承的自定义对话框