Qt元对象相关错误
Qt元对象相关错误
无法解析的外部符号 xxx QMetaObject const * __cdecl xxx::metaObject(void)const “ (?metaObject@xxx@@
意思是Qt的元对象系统不认识你的 xxx 类型。
那么有2种排查方向:
- 检查对应的函数实现有没有链到目标文件里
- 检查
xxx类型是否能被元对象系统识别
针对第2点,需要注意:
- 如果
xxx类型需要发射信号、连接槽,则记得继承QObject并添加Q_OBJECT宏。 - 如果
xxx类型不需要发射信号、连接槽,但是想要使用元对象系统的功能,记得添加Q_GADGET宏。 - 有些时候
xxx类型是作为信号槽、QVariant中的参数,这种情况需要添加qRegisterMetaType<xxx>()来将其注册到元对象系统中。
undefined reference to `vtable for XXX'
有两种出现场景:
- 当 .cpp 文件中使用了 Qt 的元对象系统,即使用了
O_OBJECT、Q_PROPERTY、signal/slot等这种需要由 moc 工具处理编译的宏时 - 当程序中出现虚函数没有实现时
解决方案
场景1:
场景1出现的原因在于最终的 Makefile 里没有将 moc_xxx.cpp 加入编译引起,而这个依赖关系是由 moc 工具写入到 makefile 中的。
Qt 的 moc 工具只会扫描 .h 头文件,因此其他后缀的文件中的 O_OBJECT 、Q_PROPERTY 将不会被处理。
这种情况的解决方案就是将所有的 O_OBJECT 、Q_PROPERTY 、signal/slot 等挪到 .h 文件,或者手动生成 moc 文件然后在用到这些元对象系统的文件末尾加上 #include "文件名.moc"
// 示例 src/plugins/qpa/main.cpp
class KWinIntegrationPlugin : public QPlatformIntegrationPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID QPlatformIntegrationFactoryInterface_iid FILE "kwin.json")
public:
using QPlatformIntegrationPlugin::create;
QPlatformIntegration *create(const QString &system, const QStringList ¶mList) override;
};
QPlatformIntegration *KWinIntegrationPlugin::create(const QString &system, const QStringList ¶mList)
{
if (!QCoreApplication::applicationFilePath().endsWith(QLatin1String("kwin_wayland")) && !qEnvironmentVariableIsSet("KWIN_FORCE_OWN_QPA")) {
// Not KWin
return nullptr;
}
if (system.compare(QLatin1String("wayland-org.kde.kwin.qpa"), Qt::CaseInsensitive) == 0) {
// create our integration
return new KWin::QPA::Integration;
}
return nullptr;
}
#include "main.moc"
kwin中还有一个引用
#include "moc_xxxx.cpp"的操作,不知道这个文件是什么。
手动生成.moc文件方法
在Qt安装目录下,找到moc.exe工具,手动生成.moc文件。


现在程序变成这样:
// 原cpp文件,末尾添加include .moc 文件
class SendMsg : public QObject
{
Q_OBJECT
};
#include "main.moc"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
SendMsg m_sendMsg;
return a.exec();
}
QObject 宏编译展开得到的虚函数声明:

moc文件中将这些虚函数实现了,因此没有找到 moc 文件就会报错:

出现这种情况的原因还可能是在执行qmake的时候.h代码里并没有 O_OBJECT 这样的代码。而执行make的时候.h里已经有 Q_OBJECT 了,解决的方法就是重新执行qmake,然后执行make。
场景2:
场景2出现的原因也有两种表象,这也提醒我们 override 关键字的好处。
如果是派生类没有实现基类的虚函数,检查并实现即可。这种情况很容易忘记实现虚析构函数,这就体现在函数声明末尾加 = default 或 {} 的好处。
如果是派生类都实现了基类的虚函数,但基类是一个抽象类(即含有纯虚函数),则就必须防止基类在某处做了模板参数。

浙公网安备 33010602011771号