Qt元对象相关错误

Qt元对象相关错误

无法解析的外部符号 xxx QMetaObject const * __cdecl xxx::metaObject(void)const “ (?metaObject@xxx@@

意思是Qt的元对象系统不认识你的 xxx 类型。

那么有2种排查方向:

  1. 检查对应的函数实现有没有链到目标文件里
  2. 检查 xxx 类型是否能被元对象系统识别

针对第2点,需要注意:

  • 如果 xxx 类型需要发射信号、连接槽,则记得继承 QObject 并添加 Q_OBJECT 宏。
  • 如果 xxx 类型不需要发射信号、连接槽,但是想要使用元对象系统的功能,记得添加 Q_GADGET 宏。
  • 有些时候 xxx 类型是作为信号槽、QVariant 中的参数,这种情况需要添加 qRegisterMetaType<xxx>() 来将其注册到元对象系统中。

undefined reference to `vtable for XXX'

有两种出现场景:

  1. 当 .cpp 文件中使用了 Qt 的元对象系统,即使用了 O_OBJECTQ_PROPERTYsignal/slot 等这种需要由 moc 工具处理编译的宏时
  2. 当程序中出现虚函数没有实现时

解决方案

场景1:

场景1出现的原因在于最终的 Makefile 里没有将 moc_xxx.cpp 加入编译引起,而这个依赖关系是由 moc 工具写入到 makefile 中的。

Qt 的 moc 工具只会扫描 .h 头文件,因此其他后缀的文件中的 O_OBJECTQ_PROPERTY 将不会被处理。

这种情况的解决方案就是将所有的 O_OBJECTQ_PROPERTYsignal/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 &paramList) override;
};

QPlatformIntegration *KWinIntegrationPlugin::create(const QString &system, const QStringList &paramList)
{
    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文件。

image

image

现在程序变成这样:

// 原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 宏编译展开得到的虚函数声明:

image

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

image

出现这种情况的原因还可能是在执行qmake的时候.h代码里并没有 O_OBJECT 这样的代码。而执行make的时候.h里已经有 Q_OBJECT 了,解决的方法就是重新执行qmake,然后执行make。

场景2:

场景2出现的原因也有两种表象,这也提醒我们 override 关键字的好处。

如果是派生类没有实现基类的虚函数,检查并实现即可。这种情况很容易忘记实现虚析构函数,这就体现在函数声明末尾加 = default{} 的好处。

如果是派生类都实现了基类的虚函数,但基类是一个抽象类(即含有纯虚函数),则就必须防止基类在某处做了模板参数。

posted @ 2024-02-20 09:29  3的4次方  阅读(1251)  评论(0)    收藏  举报