【Qt之QMetaType】使用

news2024/11/24 10:55:26

介绍

QMetaType类管理元对象系统中的命名类型。
该类用作QVariant和排队的信号与槽连接中类型的编组辅助器。它将类型名称与类型关联起来,以便可以在运行时动态创建和销毁它。使用Q_DECLARE_METATYPE()声明新类型,以使它们可供QVariant和其他基于模板的函数使用。调用qRegisterMetaType()使类型可供非基于模板的函数使用,例如排队的信号和槽连接。
可以注册具有公共默认构造函数、公共复制构造函数和公共析构函数的任何类或结构。
以下代码分配并销毁MyClass的实例:

  int id = QMetaType::type("MyClass");
  if (id != QMetaType::UnknownType) {
      void *myClassPtr = QMetaType::create(id);
      ...
      QMetaType::destroy(id, myClassPtr);
      myClassPtr = 0;
  }else{
  }

以上代码输出是:
MyClass类型未注册,则输出else语句里的内容,如果注册此类型,则输出if语句里的内容。

如果我们希望流运算符operator<<()operator>>()可以在存储自定义类型的QVariant对象上工作,则自定义类型必须提供operator<<()operator>>()运算符。

type()方法

该函数的功能是返回一个句柄(handle),该句柄指向名为 typeName 的类型(type),如果没有这样的类型,则返回 QMetaType::UnknownType

该函数可以用于在运行时(runtime)根据类型名称查找类型的元信息(meta information),并返回一个句柄以便在程序中使用该类型。如果找不到该类型,则返回一个无效句柄。

该函数属于 Qt 框架中的 QMetaType 类,用于支持动态类型(dynamic typing)。
该代码定义了 Qt 框架中的 QMetaType 类,其包含了许多用于类型信息的获取、操作和转换的成员和静态函数。

常用方法

枚举类型
类型枚举解释
TypeVoid、Bool、Int、UInt 和 UnknownType 等表示空类型、布尔类型、整型、无符号整型和未知类型。
TypeFlagNeedsConstruction、NeedsDestruction、MovableType、IsEnumeration 和 PointerToQObject 等用于表示类型的构造、析构方法需要的标识、可移动性、枚举和 QObject 指针等特征。

flags 类型 TypeFlags 是 TypeFlag 的位域版本,用于标识多个特性。

公共函数
  1. QMetaType(int typeId) 构造函数。

  2. ~QMetaType() 析构函数。

  3. void* construct(void* where, const void* copy = Q_NULLPTR) const 在给定的内存位置 where 建立一个新对象,可选择提供已有对象作为参数 copy。返回指向新对象的指针。

  4. void* create(const void* copy = Q_NULLPTR) const 创建一个新对象,可选择提供已有对象作为参数 copy。返回指向新对象的指针。

  5. void destroy(void* data) const 销毁给定对象指针 data 指向的对象。

  6. void destruct(void* data) const 对给定内存位置的对象进行析构。

  7. TypeFlags flags() const 返回类型的特性标识。

  8. bool isRegistered() const 检查该类型是否已注册。

  9. bool isValid() const 检查该类型是否有效。

  10. const QMetaObject* metaObject() const 返回类型的元对象。

  11. int sizeOf() const 返回该类型所需的内存大小。

静态公共成员
  1. bool compare(const void* lhs, const void* rhs, int typeId, int* result) 比较给定的两个对象 lhs 和 rhs 是否相等,并将结果存储在 result 中。

  2. void* construct(int type, void* where, const void* copy) 构造给定类型的对象,并将结果存储在 where 中。

  3. bool convert(const void* from, int fromTypeId, void* to, int toTypeId) 将 from 类型的对象转换成 toTypeId 类型的对象,并将结果存储在 to 中。

  4. void* create(int type, const void* copy = Q_NULLPTR) 创建指定类型的新对象,并可使用给定的 copy 作为初始化值。

  5. bool debugStream(QDebug& dbg, const void* rhs, int typeId) 输出给定类型对象 rhs 的调试信息。

  6. void destroy(int type, void* data) 销毁指定类型的给定对象 data。

  7. void destruct(int type, void* where) 析构指定类型的对象。

  8. bool equals(const void* lhs, const void* rhs, int typeId, int* result) 比较给定类型的两个对象 lhs 和 rhs 是否相等,并将结果存储在 result 中。

  9. bool hasRegisteredComparators() 检查是否已注册比较器。

  10. bool hasRegisteredComparators(int typeId) 检查是否为给定类型已注册比较器。

  11. bool hasRegisteredConverterFunction(int fromTypeId, int toTypeId) 检查是否已注册转换函数。

  12. bool hasRegisteredConverterFunction() 检查是否已注册任何转换函数。

  13. bool hasRegisteredDebugStreamOperator() 检查是否已注册调试输出函数。

  14. bool hasRegisteredDebugStreamOperator(int typeId) 检查是否为给定类型已注册调试输出函数。

  15. bool isRegistered(int type) 检查是否已注册给定类型。

  16. bool load(QDataStream& stream, int type, void* data) 从数据流 stream 中加载给定类型的对象 data。

  17. const QMetaObject* metaObjectForType(int type) 返回与给定类型关联的元对象。

  18. bool registerComparators() 注册比较器。

  19. bool registerConverter() 注册转换函数。

  20. bool registerConverter(MemberFunction function) 注册成员函数类型的转换函数。

  21. bool registerConverter(MemberFunctionOk function) 注册成员函数类型的转换函数,但不进行类型检查。

  22. bool registerConverter(UnaryFunction function) 注册一元函数类型的转换函数。

  23. bool registerDebugStreamOperator() 注册调试输出函数。

  24. bool registerEqualsComparator() 注册比较器。

  25. bool save(QDataStream& stream, int type, const void* data) 将给定类型的对象 data 写入到数据流 stream 中。

  26. int sizeOf(int type) 返回给定类型所需的内存大小。

  27. int type(const char* typeName) 返回给定类型名称的类型 ID。

  28. int type(const QByteArray& typeName) 返回给定类型名称的类型 ID。

  29. TypeFlags typeFlags(int type) 返回给定类型的特性标识。

  30. const char* typeName(int typeId) 返回给定类型 ID 的类型名称。

非成员函数
  1. int qMetaTypeId() 返回 QObject 类型的类型 ID。

  2. int qRegisterMetaType(const char* typeName) 注册给定类型名称的元类型,并返回其类型 ID。

  3. int qRegisterMetaType() 注册调用者的类型为元类型,并返回其类型 ID。

  4. void qRegisterMetaTypeStreamOperators(const char* typeName) 为给定类型名称注册流处理函数。

宏定义
  1. Q_DECLARE_ASSOCIATIVE_CONTAINER_METATYPE(Container) 声明关联式容器的元类型。

  2. Q_DECLARE_METATYPE(Type) 声明元类型。

  3. Q_DECLARE_OPAQUE_POINTER(PointerType) 声明不透明指针的元类型。

  4. Q_DECLARE_SEQUENTIAL_CONTAINER_METATYPE(Container) 声明顺序容器的元类型。

  5. Q_DECLARE_SMART_POINTER_METATYPE(SmartPointer) 声明智能指针的元类型。

示例

#include <QMetaType>
#include <QDebug>

// 自定义类型
class MyType {
public:
	MyType(){}
    MyType(int value) : m_value(value) {}
    int value() const { return m_value; }
private:
    int m_value;
};

// 注册自定义类型
Q_DECLARE_METATYPE(MyType)

int main()
{
    qRegisterMetaType<MyType>("MyType");
    // 获取自定义类型ID
    int typeID = QMetaType::type("MyType");
    if (typeID == QMetaType::UnknownType) {
        qDebug() << "MyType is not a registered type";
        return -1;
    }

    // 创建自定义类型对象
    void* obj = QMetaType::create(typeID, new MyType(42));
    MyType* myObj = static_cast<MyType*>(obj);
    qDebug() << "Value of myObj: " << myObj->value();

    // 析构自定义类型对象
    QMetaType::destroy(typeID, obj);
    delete myObj;

    return 0;
}

结果:
在这里插入图片描述
该示例中,

  • 使用 Q_DECLARE_METATYPE 宏在全局命名空间中声明了 MyType 类型是元类型。
  • 通过 QMetaType::type 函数获取 MyType 的类型 ID,如果返回值为 QMetaType::UnknownType,则说明该类型没有被注册过。

在 main 函数中,

  • 使用 QMetaType::create 函数创建一个 MyType 对象,并使用static_cast转换为 MyType 指针。
  • 输出该对象的值
  • 再使用 QMetaType::destroy 函数析构对象。

Q_DECLARE_METATYPEqRegisterMetaType用法

Q_DECLARE_METATYPEqRegisterMetaType 都是用来注册自定义类型的函数,但用途略有不同。

Q_DECLARE_METATYPE 宏用于在程序中声明自定义类型是一个元类型。这个宏只是为了告诉 Qt 该类型是元类型,并不会实际注册该类型。当使用该类型时,必须保证已经调用了 qRegisterMetaType 函数将该类型注册为元类型。例如:

// 声明自定义类型是元类型
class MyType {};
Q_DECLARE_METATYPE(MyType);

int main() {
    // 注册自定义类型为元类型
    qRegisterMetaType<MyType>("MyType");
    // ...
}

qRegisterMetaType 函数用于将自定义类型注册为元类型。它必须在程序中的一个全局作用域中调用。例如,通常将它放在 main 函数中。该函数返回已注册类型的元类型 ID,并且该 ID 可以用于在运行时创建该类型的对象。例如:

class MyType {};
Q_DECLARE_METATYPE(MyType);

int main() {
    // 注册自定义类型为元类型
    qRegisterMetaType<MyType>("MyType");

    // 获取 MyType 的元类型 ID
    int typeID = QMetaType::type("MyType");

    // 创建 MyType 对象
    MyType* obj = static_cast<MyType*>(QMetaType::create(typeID));

    // ...
}

总的来说,当你需要在运行时创建某一类型的对象,或者将某一类型用作 Qt 信号/槽中的参数或返回值时,就需要使用 qRegisterMetaType 函数来将该类型注册为元类型。而在该类型的定义头文件中,使用 Q_DECLARE_METATYPE 宏只是为了在程序中声明该类型是元类型。

使用场景

QMetaType 主要用于将 Qt 的信号与槽机制与自定义类型集成。在 Qt 中,信号与槽可以连接任何可转换为 QObject 指针的对象,但是对于信号与槽之间传输自定义类型的数据,则需要将其注册为元类型。

具体来说,当程序使用自定义类型作为信号与槽的参数或返回值时,需要使用 qRegisterMetaType 函数将该类型注册为元类型,否则程序将无法正常编译与运行。例如:

// 自定义类型
struct MyStruct {
    int value;
};

// 注册自定义类型为元类型
Q_DECLARE_METATYPE(MyStruct);
qRegisterMetaType<MyStruct>("MyStruct");

class MyObject : public QObject
{
    Q_OBJECT
public slots:
    // 槽函数,参数为 MyStruct 类型的对象
    void onCustomTypeReceived(MyStruct obj) {
        qDebug() << obj.value;
    }
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    MyObject obj;

    // 连接信号与槽,信号参数为 MyStruct 类型的对象
    QObject::connect(&sender, &Sender::customTypeSent, &obj, &MyObject::onCustomTypeReceived);

    // ...
}

除了信号与槽之外,QMetaType 还可以用于将自定义类型存储到 QVariant 对象中,以及在 QDataStream 中传输自定义类型等场景。总的来说,QMetaType 的主要作用是通过将自定义类型注册为元类型,使其能够与 Qt 的各种机制进行集成。

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

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

相关文章

民生画派创始人张龙(天驰)作品

简介 张龙&#xff08;天驰&#xff09; 中国民生画派创始人 首届“陆俨少奖”金奖得主 人民大学巨幅主题创作高级研修班导师 中央美院客座教授 神舟十二号载人飞船遨游太空搭载作品创作者 被评为2021、2022年年度最具收藏价值艺术家 中国美术家协会会员 中国美术家协…

【CesiumJS入门】(11)加载LAS点云数据

前言 最近有两次投递简历以及面试都被问到了是否有三维点云数据处理相关的经验。然而我的岗位都没有和点云相关的工作任务&#xff0c;所以还是得自己加把劲呀。 本篇将从数据获取到加载来简易地介绍一个LAS点云数据的加载。 加载数据 首先&#xff0c;你得有一份LAS格式的…

Python实验项目6 :文件操作与模块化

1、使用random库&#xff0c;产生10个100到200之间的随机数&#xff0c;并求其最大值、平均值、标准差和中位数。 # 1、使用random库&#xff0c;产生10个100到200之间的随机数&#xff0c;并求其最大值、平均值、标准差和中位数。 import random # 定义一个列表 list[] for i …

MySQL–第4关:查询用户日活数及支付金额

MySQL–第4关&#xff1a;查询用户日活数及支付金额 – WhiteNights Site 标签&#xff1a;MySQL 非常好的题&#xff0c;爱来自中国。 题目 没啥用 任务描述 现有3张业务表&#xff0c;详见如下: 需要输出结果如下&#xff0c;没有支付的日期不需要显示&#xff0c;请写出对…

Leetcode---370周赛

题目列表 2923. 找到冠军 I 2924. 找到冠军 II 2925. 在树上执行操作以后得到的最大分数 2926. 平衡子序列的最大和 一、找到冠军I 第一题模拟题&#xff0c;简单来说是看每一行(列)是否全是1&#xff0c;当然不包括自己比自己强的情况&#xff0c;需要特判 代码如下 …

python回文日期 并输出下一个ABABBABA型回文日期

题目&#xff1a; 输入&#xff1a; 输入包含一个八位整数N&#xff0c;表示日期 对于所有的测评用例&#xff0c;10000101 ≤N≤89991231&#xff0c;保证N是一个合法日期的8位数表示 输出&#xff1a; 输出两行&#xff0c;每行一个八位数。第一行表示下一个回文日期第二…

任务管理器的正确使用教程

快捷键 Ctrlshiftesc&#xff1a;进入任务管理器 我以Win11举例 如何给XX排序 给XX排序&#xff0c;点击空白处可以选择某项降序排列&#xff08;可以找到最占用某项资料的程序&#xff09;&#xff0c;再点击空白处可以选择某项升序排列 文件正在使用&#xff0c;如何解决 …

windows系统下查看安卓apk的sha1

1.在apk所在文件夹打开cmd或者powershell 2.输入 certutil -hashfile xxx.apk SHA1 这样就可以了 3.指令格式 certutil -hashfile FileName [HashAlgorithm] certutil -hashfile&#xff1a;原样输入 FileName&#xff1a;文件名 HashAlgorithm&#xff1a;可选项包括&…

简述扫码登录原理及测试要点

扫码登录本质是解决将APP端的用户登录信息&#xff08;通常是Token&#xff09;通过扫码的形式安全稳定地同步给Web端。 操作流程&#xff1a; 打开登录页面&#xff0c;展示一个二维码(web)&#xff1b;打开APP扫描该二维码后&#xff0c;APP显示确认、取消按钮(app)&#xf…

A Survey on Neural Network Interpretability

A Survey on Neural Network Interpretability----《神经网络可解释性调查》 摘要 随着深度神经网络的巨大成功&#xff0c;人们也越来越担心它们的黑盒性质。可解释性问题影响了人们对深度学习系统的信任。它还与许多伦理问题有关&#xff0c;例如算法歧视。此外&#xff0c;…

野火霸天虎 STM32F407 学习笔记_5 按键输入;位带操作介绍

输入——按键点灯 开发板按键电路如下&#xff1a; 按键未按下接地&#xff0c;按下后为高电平。电容起到消抖作用&#xff0c;软件处理就不需要手动延时消抖了。 编程没啥难度&#xff0c;就是改了一下输入模式。使用 ReadInputDataBits 读取。 //bsp_button.c #include &q…

golang 2018,go 1.19安装Gin

GOPROXYhttps://mirrors.aliyun.com/goproxy/ 一致提示URL不能有点&#xff0c;给我整郁闷了&#xff0c;换了这个地址好了 但是一致提示zip的包问题&#xff0c;最后还是不行又换回七牛 NEWBEE&#xff01; [GIN-debug] Environment variable PORT is undefined. Using por…

SAE 2.0,让容器化应用开发更简单

云原生容器化应用托管模式的演变 云原生这个概念从提出&#xff0c;到壮大&#xff0c;再到今天的极大普及&#xff0c;始终处于一个不断演进和革新的过程中。云原生体系下应用的托管形态是随着企业应用架构在不断演进的。最早的应用大多是集中式、单体式的&#xff0c;应用通…

多元高斯分布

下面我们来看一下多元高斯分布&#xff0c;叫做 multivariative 高斯分布&#xff0c;也就是目前的情况是向量的形式&#xff0c;也就是说我的 x 它是一个向量&#xff0c;那这个情况下我们的高斯分布应该怎么去表示&#xff1f;我们这里面重点还是来看一下它的一个表示的方法&…

【Linux系统编程十五】:(基础IO2)--重定向实现原理 “Linux下一切皆文件“

【Linux系统编程十五】&#xff1a;重定向原理 与 "Linux下一切皆文件" 一.重定向1.实现原理2.输出重定向3.输入重定向4.补充&#xff1a;简易shell中实现重定向 二."Linux下一切皆文件"1.虚拟文件系统(VFS) 一.重定向 我们首先关闭2号文件描述符&#xff…

HTTP协议 和 HTTPS协议

一、HTTP协议&#xff1a; HTTP协议是超文本传输协议的缩写&#xff0c;英文是Hyper Text Transfer Protocol。它是从WEB服务器传输超文本标记语言(HTML)到本地浏览器的传送协议。 设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。HTPP有多个版本&#xff0c;目前…

Read Completion Boundary (RCB)切分规则

Read Completion Boundary(RCB) 切分规则 Read Completion Boundary(RCB) 简介 当Read Completion 包含multi-completions时&#xff0c;RCB 规定了多个Completions地址的align规则。Spec中规定RCB可以是64 Byte或者128 Byte&#xff0c;该值可以在link_control register中得…

什么是观察者模式?用 Python 如何实现 Observer(观察者或发布订阅)对象行为型模式?

什么是观察者模式&#xff1f; 观察者模式&#xff08;Observer pattern&#xff09;是一种行为型设计模式&#xff0c;它允许对象之间建立一种一对多的依赖关系&#xff0c;当一个对象的状态发生变化时&#xff0c;其相关依赖对象都会得到通知并自动更新。 在观察者模式中&am…

Leo赠书活动-06期 【强化学习:原理与Python实战】文末送书

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; 赠书活动专栏 ✨特色专栏&#xff1a;…

CVE-2023-0179-Nftables整型溢出

前言 Netfilter是一个用于Linux操作系统的网络数据包过滤框架&#xff0c;它提供了一种灵活的方式来管理网络数据包的流动。Netfilter允许系统管理员和开发人员控制数据包在Linux内核中的处理方式&#xff0c;以实现网络安全、网络地址转换&#xff08;Network Address Transl…