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
顺便说一句,在>接收信号处有一个输入错误,不能有一个实现(这将由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继承的自定义对话框