【Qt】插件Plugin入门之Q_PLUGIN_METADATA()宏【2023.05.07】

news2024/12/23 14:38:17

摘要

  分析Q_PLUGIN_METADATA宏的设计意图,站在设计者的意图进行插件的高屋建瓴式学习。

Meta-Object Compiler 简称MOC

  Qt 的 Meta-Object Compiler(MOC)是一个预处理器,用于处理带有特殊关键字的 C ++ 文件,并生成用于 Qt 的元对象代码。这是因为 Qt 提供了信号和槽机制,允许对象之间的通信。为了实现这一点,Qt 通过在每个QObject衍生类上创建一个“元对象”来动态识别其成员函数和其它属性,例如它们是否是信号或槽。

  MOC 是 Qt 的一部分,在安装 Qt 的时候会安装。在 Qt 的开发中,当 .h 文件中的 QObject 衍生类含有 Q_OBJECT 宏时,必须通过 MOC 来进行预处理,生成额外的元数据。

  MOC 的工作方式是扫描包含 Q_OBJECT 宏的 .h 文件,创建元数据并生成对应的 C++ 代码。此后,开发人员将使用 C++ 代码连接此元数据,以便在代码中使用信号和槽的机制。

Q_PLUGIN_METADATA宏的作用

  Qt插件是把一组功能进行封装,以静态库和动态库的形式提供给程序调用。在学习Qt之前,我已经知道了C++动态库就是把功能封装,通过导出函数的方式供调用者调用。C++动态库是通过dllexport关键字,告诉编译器把函数或类进行导出,动态库只有被导出的函数才能被调用方(外部)找到。

  Qt插件是在C++动态库基础之上进行的扩展,支持了信号-槽等新特性。Qt插件也需要告诉MOC导出了哪些函数、类。Qt中通过宏Q_PLUGIN_METADATA告诉MOC,哪个类被导出,也就是哪个类供外部调用。

*.h *.cpp文件、Q_PLUGIN_METADATA宏、MOC的关系图

在这里插入图片描述

上代码

  分析这个Q_PLUGIN_METADATA宏会使得MOC生成了哪些代码。先看下面的头文件。IID是给插件导处的类起个唯一的名字(字符串的形式),底层是个GUID。FILE是给插件属性信息指定个配置文件,暂时没用到先不管。

#ifndef ACCESSIBLEPLUGIN_H
#define ACCESSIBLEPLUGIN_H

#include <QAccessiblePlugin>

class AccessiblePlugin : public QAccessiblePlugin
{
    Q_OBJECT
    Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QAccessibleFactoryInterface" FILE "simplePlugin.json")

public:
    explicit AccessiblePlugin(QObject *parent = nullptr);

private:
    QAccessibleInterface *create(const QString &key, QObject *object) override;
};

#endif // ACCESSIBLEPLUGIN_H

  我们看下编译后生成了些啥😱。如下是MOC编译出的 moc_accessibleplugin.cpp 文件。


/****************************************************************************
** Meta object code from reading C++ file 'accessibleplugin.h'
**
** Created by: The Qt Meta Object Compiler version 67 (Qt 5.9.9)
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/

#include "../../simplePlugin/accessibleplugin.h"
#include <QtCore/qbytearray.h>
#include <QtCore/qmetatype.h>
#include <QtCore/qplugin.h>
#if !defined(Q_MOC_OUTPUT_REVISION)
#error "The header file 'accessibleplugin.h' doesn't include <QObject>."
#elif Q_MOC_OUTPUT_REVISION != 67
#error "This file was generated using the moc from 5.9.9. It"
#error "cannot be used with the include files from this version of Qt."
#error "(The moc has changed too much.)"
#endif

QT_BEGIN_MOC_NAMESPACE
QT_WARNING_PUSH
QT_WARNING_DISABLE_DEPRECATED
struct qt_meta_stringdata_AccessiblePlugin_t {
    QByteArrayData data[1];
    char stringdata0[17];
};
#define QT_MOC_LITERAL(idx, ofs, len) \
    Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \
    qptrdiff(offsetof(qt_meta_stringdata_AccessiblePlugin_t, stringdata0) + ofs \
        - idx * sizeof(QByteArrayData)) \
    )
static const qt_meta_stringdata_AccessiblePlugin_t qt_meta_stringdata_AccessiblePlugin = {
    {
QT_MOC_LITERAL(0, 0, 16) // "AccessiblePlugin"

    },
    "AccessiblePlugin"
};
#undef QT_MOC_LITERAL

static const uint qt_meta_data_AccessiblePlugin[] = {

 // content:
       7,       // revision
       0,       // classname
       0,    0, // classinfo
       0,    0, // methods
       0,    0, // properties
       0,    0, // enums/sets
       0,    0, // constructors
       0,       // flags
       0,       // signalCount

       0        // eod
};

void AccessiblePlugin::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
    Q_UNUSED(_o);
    Q_UNUSED(_id);
    Q_UNUSED(_c);
    Q_UNUSED(_a);
}

const QMetaObject AccessiblePlugin::staticMetaObject = {
    { &QAccessiblePlugin::staticMetaObject, qt_meta_stringdata_AccessiblePlugin.data,
      qt_meta_data_AccessiblePlugin,  qt_static_metacall, nullptr, nullptr}
};


const QMetaObject *AccessiblePlugin::metaObject() const
{
    return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
}

void *AccessiblePlugin::qt_metacast(const char *_clname)
{
    if (!_clname) return nullptr;
    if (!strcmp(_clname, qt_meta_stringdata_AccessiblePlugin.stringdata0))
        return static_cast<void*>(this);
    return QAccessiblePlugin::qt_metacast(_clname);
}

int AccessiblePlugin::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
    _id = QAccessiblePlugin::qt_metacall(_c, _id, _a);
    return _id;
}

QT_PLUGIN_METADATA_SECTION const uint qt_section_alignment_dummy = 42;

#ifdef QT_NO_DEBUG

QT_PLUGIN_METADATA_SECTION
static const unsigned char qt_pluginMetaData[] = {
    'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', ' ',
    'q',  'b',  'j',  's',  0x01, 0x00, 0x00, 0x00,
    0xd4, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
    0xc0, 0x00, 0x00, 0x00, 0x1b, 0x03, 0x00, 0x00,
    0x03, 0x00, 'I',  'I',  'D',  0x00, 0x00, 0x00,
    '-',  0x00, 'o',  'r',  'g',  '.',  'q',  't', 
    '-',  'p',  'r',  'o',  'j',  'e',  'c',  't', 
    '.',  'Q',  't',  '.',  'Q',  'A',  'c',  'c', 
    'e',  's',  's',  'i',  'b',  'l',  'e',  'F', 
    'a',  'c',  't',  'o',  'r',  'y',  'I',  'n', 
    't',  'e',  'r',  'f',  'a',  'c',  'e',  0x00,
    0x1b, 0x0b, 0x00, 0x00, 0x09, 0x00, 'c',  'l', 
    'a',  's',  's',  'N',  'a',  'm',  'e',  0x00,
    0x10, 0x00, 'A',  'c',  'c',  'e',  's',  's', 
    'i',  'b',  'l',  'e',  'P',  'l',  'u',  'g', 
    'i',  'n',  0x00, 0x00, ':',  '!',  0xa1, 0x00,
    0x07, 0x00, 'v',  'e',  'r',  's',  'i',  'o', 
    'n',  0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
    0x05, 0x00, 'd',  'e',  'b',  'u',  'g',  0x00,
    0x15, 0x13, 0x00, 0x00, 0x08, 0x00, 'M',  'e', 
    't',  'a',  'D',  'a',  't',  'a',  0x00, 0x00,
    '(',  0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
    '$',  0x00, 0x00, 0x00, 0x14, 0x03, 0x00, 0x00,
    0x04, 0x00, 'K',  'e',  'y',  's',  0x00, 0x00,
    0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
    0x0c, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00,
    'H',  0x00, 0x00, 0x00, '|',  0x00, 0x00, 0x00,
    'l',  0x00, 0x00, 0x00
};

#else // QT_NO_DEBUG

QT_PLUGIN_METADATA_SECTION
static const unsigned char qt_pluginMetaData[] = {
    'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', ' ',
    'q',  'b',  'j',  's',  0x01, 0x00, 0x00, 0x00,
    0xd4, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00,
    0xc0, 0x00, 0x00, 0x00, 0x1b, 0x03, 0x00, 0x00,
    0x03, 0x00, 'I',  'I',  'D',  0x00, 0x00, 0x00,
    '-',  0x00, 'o',  'r',  'g',  '.',  'q',  't', 
    '-',  'p',  'r',  'o',  'j',  'e',  'c',  't', 
    '.',  'Q',  't',  '.',  'Q',  'A',  'c',  'c', 
    'e',  's',  's',  'i',  'b',  'l',  'e',  'F', 
    'a',  'c',  't',  'o',  'r',  'y',  'I',  'n', 
    't',  'e',  'r',  'f',  'a',  'c',  'e',  0x00,
    0x15, 0x0b, 0x00, 0x00, 0x08, 0x00, 'M',  'e', 
    't',  'a',  'D',  'a',  't',  'a',  0x00, 0x00,
    '(',  0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
    '$',  0x00, 0x00, 0x00, 0x14, 0x03, 0x00, 0x00,
    0x04, 0x00, 'K',  'e',  'y',  's',  0x00, 0x00,
    0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00,
    0x1b, 0x12, 0x00, 0x00, 0x09, 0x00, 'c',  'l', 
    'a',  's',  's',  'N',  'a',  'm',  'e',  0x00,
    0x10, 0x00, 'A',  'c',  'c',  'e',  's',  's', 
    'i',  'b',  'l',  'e',  'P',  'l',  'u',  'g', 
    'i',  'n',  0x00, 0x00, '1',  0x00, 0x00, 0x00,
    0x05, 0x00, 'd',  'e',  'b',  'u',  'g',  0x00,
    ':',  '!',  0xa1, 0x00, 0x07, 0x00, 'v',  'e', 
    'r',  's',  'i',  'o',  'n',  0x00, 0x00, 0x00,
    0x0c, 0x00, 0x00, 0x00, 'H',  0x00, 0x00, 0x00,
    0x80, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00,
    0xb0, 0x00, 0x00, 0x00
};
#endif // QT_NO_DEBUG

QT_MOC_EXPORT_PLUGIN(AccessiblePlugin, AccessiblePlugin)

QT_WARNING_POP
QT_END_MOC_NAMESPACE


🍖最大的块头static const unsigned char qt_pluginMetaData[] = {}; 这是一个字符串数组,里面存储的插件的信息。整理下排版如下:

//非Debug版
QTMETADATA  qbjs1   d4   b   c0   1b3  3 
IID   - org.qt-project.Qt.QAccessibleFactoryInterface 1bb  9 
className 10 AccessiblePlugin  :!a1 7 
version   11   5 
debug 1513  8 
MetaData  (   3   $   143  4 Keys  c           c   c   88   H   |   l



//Debug版
QTMETADATA  qbjs1   d4   b   c0   1b3  3 
IID   - org.qt-project.Qt.QAccessibleFactoryInterface 15b  8 
MetaData  **********
className 10 AccessiblePlugin  31   5 
debug :!a1 7 
version   c   H   80   a4   b0

这两个版本都有IID信息和className。IID字符串和宏里面定义的字符串是一样的,记住IID是导出类的身份ID。className 就是我们插件导出的类名。


回到Q_PLUGIN_METADATA宏的作用

  上文分析了宏对moc文件的影响,最明显的是这个宏影响了moc文件的字符数组qt_pluginMetaData的值。Qt的MOC通过这个字符数组知道插件的导出类名、IID的值等信息。正如我们通过dllexport函数告诉C++编译器,要导出某个类一样,只不过这个宏是告诉Qt的MOC要导出的类。

// 进一步的分析需要对MOC、 META-DATA、 QObject、 d指针有深入的剖析。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/500242.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux命令·netstat

netstat命令用于显示与IP、TCP、UDP和ICMP协议相关的统计数据&#xff0c;一般用于检验本机各端口的网络连接情况。netstat是在内核中访问网络及相关信息的程序&#xff0c;它能提供TCP连接&#xff0c;TCP和UDP监听&#xff0c;进程内存管理的相关报告。 如果你的计算机有时候…

详细版简单易学版TypeScript各类型声明

假如本地新建了一个b.ts文件 安装TypeScript&#xff1a;npm install -g typescript 编译代码&#xff1a;tsc b.ts 运行js&#xff1a;node b.js 在终端输入 tsc -init 生成 tsconfig.json 文件 类型注解&#xff1a;TypeScript里的类型注解是一种轻量级的为函数或变量添加约束…

Python中模块和包基础学习

目录 模块 引入模块 使用from...import语句引入模块中的指定变量或函数 使用import...as语句给模块起别名 使用dir()函数查看模块中的所有变量和函数 使用__name__变量判断模块是被导入还是直接执行 包 注意 示例 模块 Python中的模块是指一个文件&#xff0c;可以包…

2.1 掌握NumPy数组对象ndarray

2.1 掌握NumPy数组对象ndarray 2.2.1 创建数组对象1&#xff0e;数组创建2&#xff0e;数组属性&#xff1a;ndarray&#xff08;数组&#xff09;是存储单一数据类型的多维数组。3&#xff0e;数组数据类型 2.1.2 生成随机数random模块常用随机数生成函数 2.1.3 通过索引访问数…

Python中异常处理的学习

目录 异常的基本介绍 异常处理语句 抛出异常 异常的基本介绍 在Python中&#xff0c;如果程序出现错误&#xff0c;会抛出异常。异常是一种Python对象&#xff0c;它封装了错误的信息&#xff0c;并提供了一种处理错误的机制。Python中内置了很多异常类型&#xff0c;包括但…

C语言-学习之路-07

C语言-学习之路-07 内存管理作用域局部变量静态&#xff08;static&#xff09;局部变量全局变量extern全局变量声明全局函数和静态函数 内存分布内存分区 内存管理 作用域 C语言中变量的作用域可分为&#xff1a;代码作用域、函数作用域、文件作用域 局部变量 局部变量也叫…

C嘎嘎~~ [类 下篇(2)]

类 下篇2 5.赋值运算符重载5.1运算符重载5.1.1 运算符的概念5..1.2 重载运费符的位置5.1.3运算符重载的实质 5.2 赋值运算符重载5.2.1深刻理解---编译器生成的默认赋值运算符重载5.2.2深刻理解---拷贝构造和赋值运算符重载5.2.3深刻理解---传参和返回值用引用修饰 5.赋值运算符…

ADAS-透视前方:汽车HUD技术原理解析

“ 当人们谈论未来的汽车技术时&#xff0c;汽车HUD&#xff08;Head-Up Display&#xff09;是一个经常被提及的技术。HUD是一种驾驶辅助技术&#xff0c;它可以将关键的驾驶信息直接显示在驾驶员的视线范围内&#xff0c;让驾驶员无需转移视线就能获得所需信息。这个技术在过…

HZNUCTF2023 web

目录 <1> guessguessguess <2> ezflask(无过滤ssti) ​ <3> ppppop(cookie泄露反序列化) <4> ezlogin(bool盲注) <5> ezpickle(pickle反序列化) <6> eznode(原型链污染) <1> guessguessguess 尝试是否存在sql注入&#xff0c;…

03- 目标检测数据集和标注工具介绍 (目标检测)

要点&#xff1a; 常用数据集和标注工具 标注工具 PPOCRLabel github地址&#xff1a;paddleocrlabel 参考文档&#xff1a;目标检测简介 - 知乎 一 目标检测数据集 1. PASCAL VOC VOC数据集是目标检测经常用的一个数据集&#xff0c;自2005年起每年举办一次比赛&#xff…

JWT快速入门及日常使用

什么是JWT JSON Web Token&#xff0c;通过数字签名的方式&#xff0c;以json对象为载体&#xff0c;在不同服务端之间安全的传输信息 JWT有什么用 JWT最常见的场景就是授权认证&#xff0c;一旦用户登录&#xff0c;后续每个请求都将包含JWT&#xff0c;系统每次处理用户请求前…

总结下自己编译alembic的过程

编译alembic过程回顾 前言 总结下自己编译alembic的过程 最近想学习编译啥的&#xff0c;就想着一边编译着&#xff0c;一边学习的&#xff0c;刚好&#xff0c;拿alembic编译练手&#xff0c;记录下自己编译的过程吧。 编译的使用的是Visual Studio 2022&#xff0c;python…

【性能设计篇】性能设计-缓存

前言 在分布式系统中&#xff0c;最耗费性能的地方就是数据库&#xff0c;而对于数据库的操作基本上就是添加&#xff0c;修改&#xff0c;删除和查询&#xff0c;对于前3者来说&#xff0c;基本上不会出现性能瓶颈。最耗费性能的地方就是查询了&#xff0c;对于查询有join、w…

Kafka相关知识

一、基本概念及流程 Broker:kafka集群中的实例Topic:队列的主题,逻辑概念;Partition:Topic分区,物理概念,同意parttion内消息有序;Producer & Consumer:生产消息的客户端 & 消费消息的客户端,kafka认为是服务器。将每个Topic划分为多个分区Partition,每个分…

Vim (NeoVim) 配置

Vim 基础 模式 o 代表的是open a new line i 代表的是insert a 代表的是append Visual [Character] 视觉模式&#xff1a;用于选择单个字符&#xff08;v小写’v’&#xff09;视觉线模式&#xff1a;用于一次选择整条线&#xff08;V大写“V”&#xff09;视觉块模式&#…

深度学习数据集—动物数据集大合集(二)

近期又整理了一批各类动物数据集&#xff0c;分享给大家。废话不多说&#xff0c;直接上干货&#xff01;&#xff01; 1、151种动物图片数据集共6271张&#xff0c;图片大小&#xff1a;224x224 jpg ​ ​ 下载地址&#xff1a;151种动物图片数据集 2、9种海洋生物&#xff0…

C++学习之字符常量、字符串常量和符号常量的区别

字符常量 字符常量就是把一个字符用单引号括起来。 注&#xff1a; 字符常量只能包含一个字符&#xff0c;如’AB’是不合法的字符常量区分大小写字母单引号“ ’ ”是定界符&#xff0c;而不属于字符常量的一部分 字符串常量 字符串常量时用双引号括起来的字符序列。 举例…

kill 命令信号详解

信号 列出所有信号 $ kill -l1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18…

【数据结构】交换排序(详细)

交换排序 1. 冒泡排序2. 快速排序2.1霍尔版本2.2 挖坑法2.3 前后指针法&#xff08;最优&#xff09;2.4 小区间优化2.5 非递归快排 1. 冒泡排序 思想 排升序&#xff1a;每趟将前后两元素进行比较&#xff0c;按照“前小后大”进行交换&#xff0c;将最大的元素放在最后。 排…

Solr(3):Solr的名词解释及配置文件说明

1 名称解释 1.1 索引库 我们导入数据&#xff0c;solr 会被它以某种格式保存在索引库里面&#xff01; 可以看出刚安装的现在没有任何索引库 1.2 索引分词 Solr在导入数据库时&#xff0c;会对某些语句进行分词 1.3 搜索分词 Solr在搜索数据库时&#xff0c;会对某些语句进…