Qt元对象系统分析小记

目录

为什么是Qt元对象系统

关于Qt元对象的进一步分析

QMetaObjectAPI列表

Reference


笔者打算深入研究一下Qt元对象,这里将分析结果记录一下:

为什么是Qt元对象系统

第一个问题:什么是元对象?

首先,原生的C++,是没有反射这个概念的。或者说,我们没有办法使用标准直接快速的获取类的所有信息:比如说快速取到表达类名的字符串,类方法的字符串等等。即使广大编译器有了各种各样的支持,但是C++的实现自由就导致了每一个编译器的实现方式不一样,我们书写的程序非常难以实现通用。

Qt提供了更为强大的元对象(Meta-Object)系统机制来实现动态获取类型信息,以及扩展我们的原生C++:

功能描述
元对象类每个QObject子类都有一个对应的元对象类,提供对象的名称、属性、信号和槽的信息。
信号和槽支持对象之间的通信机制,信号发送时可以连接到一个或多个槽,处理相应的事件。
动态属性可以在运行时为对象添加、修改或删除属性,增加了对象的灵活性。
类型信息提供运行时类型识别功能,允许检查对象的类型并进行相应处理。
Qt MOC元对象编译器,解析信号和槽,生成相应的代码以支持元对象功能。
反射允许在运行时获取对象的元信息,比如可以列出所有属性、信号和槽等。
国际化支持通过元对象系统,可以方便地处理字符串的翻译,支持多语言应用。
对象树通过父子关系管理对象的生命周期,父对象可以自动删除子对象。

上面这个表格记录了Qt元对象系统的主要功能和特性。现在,我们对Qt元对象系统有了一个大致的Framework了!但是只知道这些貌似跟没说一样。我们下一步来深入Qt元对象系统。

关于Qt元对象的进一步分析

Qt 的元对象系统提供了用于对象间通信的信号和槽机制、运行时类型信息和动态属性系统。

元对象系统基于三件非常重要的东西:

  • QObject 类为可以利用元对象系统的对象提供了基类。

  • Q_OBJECT 宏用于启用元对象功能,例如动态属性、信号和槽。

  • 元对象编译器 (moc) 为每个 QObject 子类提供实现元对象功能所需的代码。

moc 工具读取 C++ 源文件。如果它发现一个或多个包含 Q_OBJECT 宏的类声明,它会生成另一个 C++ 源文件,其中包含每个类的元对象代码。生成的源文件要么被 #include 到类的源文件中,要么更常见的是编译并与类的实现链接。 除了提供用于对象间通信的信号和槽机制(引入系统的主要原因)之外,元对象代码还提供以下附加功能:

  • QObject::metaObject() 返回与该类相关的元对象。

  • QMetaObject::className() 在运行时以字符串形式返回类名,无需通过 C++ 编译器支持本机运行时类型信息 (RTTI)。

  • QObject::inherits() 函数返回某个对象是否是继承 QObject 继承树中指定类的类的实例。

  • QObject::tr() 翻译字符串以实现国际化。

  • QObject::setProperty() 和 QObject::property() 通过名称动态设置和获取属性。

  • QMetaObject::newInstance() 构造该类的新实例。

现在我们大概可以猜到:Qt实现元对象系统其实就是依靠三个部分:一个QObject原生类提供接口,Q_OBJECT也就是内部封装的QMetaObject实际上是就是实现Qt元对象主要功能的。下一步就是moc编译器实际上生成源代码。三者缺一不可。

/* qmake ignore Q_OBJECT */
#define Q_OBJECT \
public: \QT_WARNING_PUSH \Q_OBJECT_NO_OVERRIDE_WARNING \static const QMetaObject staticMetaObject; \virtual const QMetaObject *metaObject() const; \virtual void *qt_metacast(const char *); \virtual int qt_metacall(QMetaObject::Call, int, void **); \QT_TR_FUNCTIONS \
private: \Q_OBJECT_NO_ATTRIBUTES_WARNING \Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); \QT_WARNING_POP \struct QPrivateSignal { explicit QPrivateSignal() = default; }; \QT_ANNOTATE_CLASS(qt_qobject, "")

qobject_cast是一个类似于dynamic_cast的函数,当然他是读取元信息进行转换的!对于转换不成功行为也是返回空!

if (QLabel *label = qobject_cast<QLabel *>(obj)) {label->setText(tr("Ping"));} else if (QPushButton *button = qobject_cast<QPushButton *>(obj)) {button->setText(tr("Pong!"));
}

虽然可以使用 QObject 作为基类,而无需 Q_OBJECT 宏和元对象代码,但如果不使用 Q_OBJECT 宏,则信号和槽以及此处描述的其他功能都将不可用。从元对象系统的角度来看,没有元代码的 QObject 子类相当于其具有元对象代码的最近祖先。

这意味着,例如,QMetaObject::className() 将不会返回您的类的实际名称,而是返回此祖先的类名。 因此,强烈建议 QObject 的所有子类都使用 Q_OBJECT 宏,无论它们是否实际使用信号、槽和属性

QMetaObjectAPI列表

API描述
const QMetaObject *metaObject()返回与对象关联的元对象。
QString className() const返回类名的字符串表示。
bool inherits(const char *name) const检查对象是否是指定类或其子类的实例。
int methodCount() const返回方法的数量。
QMetaMethod method(int index) const返回指定索引的元方法。
int propertyCount() const返回属性的数量。
QMetaProperty property(int index) const返回指定索引的元属性。
int enumeratorCount() const返回枚举的数量。
QMetaEnum enumerator(int index) const返回指定索引的元枚举。
QMetaObject *superClass() const返回超类的元对象。
QMetaObject::Constructor constructor(int index)返回指定索引的构造函数。
QMetaMethod method(const char *signature)根据签名返回对应的元方法。
QMetaProperty property(const char *name)根据属性名返回对应的元属性。
QMetaObject::PropertyFlags propertyFlags(const char *name)返回属性的标志。
QVariant property(const char *name) const获取指定属性名的值。
bool setProperty(const char *name, const QVariant &value)设置指定属性名的值。

关于使用上,需要记得

  1. 继承QObject

  2. 使用Q_OBJECT宏

满足这些就可以使用Qt元对象类信息的使用,但是,属性信息不行!到底如何,请听下回分解

Reference

The Meta-Object System | Qt Core 6.8.0

Qt中的元对象系统(Meta-Object System) - 知乎 (zhihu.com)

QMetaObject Struct | Qt Core 6.8.0

Qt's Property System

表格:所有API:

API描述
QMetaObject()构造函数。
const QMetaObject *metaObject() const返回与对象关联的元对象。
QString className() const返回类名的字符串表示。
bool inherits(const char *name) const检查对象是否是指定类或其子类的实例。
int methodCount() const返回方法的数量。
QMetaMethod method(int index) const返回指定索引的元方法。
int propertyCount() const返回属性的数量。
QMetaProperty property(int index) const返回指定索引的元属性。
int enumeratorCount() const返回枚举的数量。
QMetaEnum enumerator(int index) const返回指定索引的元枚举。
QMetaObject *superClass() const返回超类的元对象。
QMetaMethod method(const char *signature) const根据签名返回对应的元方法。
QMetaProperty property(const char *name) const根据属性名返回对应的元属性。
QMetaObject::PropertyFlags propertyFlags(const char *name) const返回属性的标志。
QVariant property(const char *name) const获取指定属性名的值。
bool setProperty(const char *name, const QVariant &value)设置指定属性名的值。
QMetaObject::Constructor constructor(int index) const返回指定索引的构造函数。
int constructorCount() const返回构造函数的数量。
QMetaMethod constructor(int index) const返回指定索引的构造函数元方法。
QMetaMethod signal(int index) const返回指定索引的信号。
int signalCount() const返回信号的数量。
QMetaMethod slot(int index) const返回指定索引的槽。
int slotCount() const返回槽的数量。
int indexOfMethod(const char *signature) const根据签名返回方法的索引。
int indexOfSignal(const char *signal) const根据信号返回信号的索引。
int indexOfSlot(const char *slot) const根据槽返回槽的索引。
int indexOfProperty(const char *name) const根据属性名返回属性的索引。
int indexOfEnumerator(const char *name) const根据枚举名返回枚举的索引。
QMetaEnum enumerator(const char *name) const根据枚举名返回对应的元枚举。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

YOLO系列入门:1、YOLO V11环境搭建

YOLO了解 yolo检测原理 yolo是目标检测模型&#xff0c;目标检测包含物体分类、位置预测两个内容。目前yolo的开发公司官网为&#xff1a;https://docs.ultralytics.com/zh截止到目前2024年10月&#xff0c;最新的是yolo11。关于YOLO的介绍可以参考这篇文章&#xff1a;https…

Python+Django+VUE 搭建深度学习训练界面 (持续ing)

PythonDjangoVUE 搭建深度学习训练界面 &#xff08;持续ing&#xff09; 环境说明 Pycharm 专业版2024.1.4&#xff0c;社区版不支持网页开发 下载链接&#xff1a;https://www.jetbrains.com/pycharm/download/other.html 参考链接&#xff1a;https://www.quanxiaoha.co…

es实现桶聚合

目录 聚合 聚合的分类 DSL实现桶聚合 dsl语句 结果 聚合结果排序 限定聚合范围 总结 聚合必须的三要素&#xff1a; 聚合可配置的属性 DSL实现metric聚合 例如&#xff1a;我们需要获取每个品牌的用户评分的min,max,avg等值 只求socre的max 利用RestHighLevelClien…

BIO,NIO,直接内存,零拷贝

前置知识 什么是Socket&#xff1f; Socket是应用层与TCP/IP协议族通信的中间软件抽象层&#xff0c;它是一组接口&#xff0c;一般由操作系统提供。在设计模式中&#xff0c;Socket其实就是一个门面模式&#xff0c;它把复杂的TCP/IP协议处理和通信缓存管理等等都隐藏在Sock…

vue3使用i18n做国际化多语言,实现常量跟随语言切换翻译

因为我有一个常量的配置文件在项目中&#xff0c;而且有中文内容&#xff0c;我想在切换语言的时候&#xff0c;跟着这个翻译也实时切换&#xff0c;就可以使用computed计算属性实现。 把name改成下面的样子&#xff1a; name: computed(() > t(pad.regularMode)), 就可以…

分享一款录屏、直播软件

光音录屏 光音录屏 是新一代的录屏工具&#xff0c;跟传统录屏工具相比&#xff0c;它不仅可以录制屏幕&#xff0c;还可以同时录制「人像 屏幕」&#xff0c;此外它还提供了美颜、虚拟背景、绿幕抠像、图片、文本编辑、字幕、白板等更多高级功能。你可以将录制好的视频&…

ue5实现数字滚动增长

方法1 https://www.bilibili.com/video/BV1h14y197D1/?spm_id_from333.999.0.0 b站教程 重写loop节点 方法二 写在eventtick里

ffmpeg视频滤镜: 色温- colortemperature

滤镜简述 colortemperature 官网链接 》 FFmpeg Filters Documentation 这个滤镜可以调节图片的色温&#xff0c;色温值越大显得越冷&#xff0c;可以参考一下下图&#xff1a; 咱们装修的时候可能会用到&#xff0c;比如选择灯还有地板的颜色的时候&#xff0c;选暖色调还是…

多厂商的实现不同vlan间通信

Cisco单臂路由 Cisco路由器配置 -交换机配置 -pc配置 华三的单臂路由 -路由器配置 -华三的接口默认是打开的 -pc配置及ping的结果 -注意不要忘记配置默认网关 Cisco-SVI -交换机的配置 -创建vlan -> 设置物理接口对应的Acess或Trunk -> 进入vlan接口&#xff0c;打开接…

【纯血鸿蒙】HarmonyOS和OpenHarmony 的区别

一、开源鸿蒙&#xff08;Open Harmony&#xff09; 鸿蒙系统愿来的设计初衷&#xff0c;就是让所有设备都可以运行一个系统&#xff0c;但是每个设备的运算能力和功能都不同&#xff0c;所以内核的设计上&#xff0c;采用了微内核的设计&#xff0c;除了最基础的功能放在内核…

mfc之tab标签控件的使用--附TabSheet源码

TabSheet源码 TabSheet.h #if !defined(AFX_TABSHEET_H__42EE262D_D15F_46D5_8F26_28FD049E99F4__INCLUDED_) #define AFX_TABSHEET_H__42EE262D_D15F_46D5_8F26_28FD049E99F4__INCLUDED_#if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 // TabSheet.h : …

C++面向对象编程学习

C面向对象编程学习 前言一、C面向对象编程二、知识点学习1. 定义一个类1.1 使用struct定义1.2 使用class定义1.3 struct和class的区别 2. 类的定义方式2.1 单文件定义&#xff08;Inline Definition&#xff09;2.2 分离定义&#xff08;Separate Definition&#xff09;2.3 头…

[bug] vllm 0.6.1 RuntimeError: operator torchvision::nms does not exist

[bug] vllm 0.6.1 RuntimeError: operator torchvision::nms does not exist 环境 python 3.10 torch 2.4.0cu118 torchvision 0.19.0cu118 vllm 0.6.1.post2cu118问题详情 if torch._C._d…

【华为路由】OSPF多区域配置

网络拓扑 设备接口地址 设备 端口 IP地址 RTA Loopback 0 1.1.1.1/32 G0/0/0 10.1.1.1/24 RTB Loopback 0 2.2.2.2/32 G0/0/0 10.1.1.2/24 G0/0/1 10.1.2.1/24 RTC Loopback 0 3.3.3.3/32 G0/0/0 10.1.2.2/24 G0/0/1 10.1.3.1/24 RTD Loopback 0 4.4.4…

【Jenkins】解决在Jenkins Agent节点容器内无法访问物理机的docker和docker compose的问题

解决在Jenkins Agent节点容器内无法访问物理机的docker和docker compose的问题 1. 确定物理机docker和docker compose已经安装2. 编写Jenkins Agent结点docker-compose.yaml配置文件3. 修改docker运行时文件权限4. 启动容器并验证 最近接触到一个发布产物是一个 docker镜像的项…

【K8s】Kubernetes 证书管理工具 Cert-Manager

本文内容均来自个人笔记并重新梳理&#xff0c;如有错误欢迎指正&#xff01; 如果对您有帮助&#xff0c;烦请点赞、关注、转发、订阅专栏&#xff01; 专栏订阅入口 | 精选文章 | Kubernetes | Docker | Linux | 羊毛资源 | 工具推荐 | 往期精彩文章 【Docker】&#xff08;全…

Github优质项目推荐(第八期)

文章目录 Github优质项目推荐 - 第八期一、【manim】&#xff0c;66.5k stars - 创建数学动画的 Python 框架二、【siyuan】&#xff0c;19.5k stars - 个人知识管理软件三、 【GetQzonehistory】&#xff0c;1.3k stars - 获取QQ空间发布的历史说说四、【SecLists】&#xff0…

【Linux系统编程】冯诺依曼体系结构与操作系统

目录 1、冯诺依曼体系结构 1.1 冯诺依曼体系结构的组成 1.2 程序运行时必须要加载到内存 1.3 数据通信 1.4 为什么要有内存 2、操作系统 2.1 概念 2.2 设计OS的目的 2.3 如何理解管理 2.4 系统调用和库函数的概念 1、冯诺依曼体系结构 我们常见的计算机&#xff0c;如…

transforms的使用

示例代码 from PIL import Image from torch.utils.tensorboard import SummaryWriter from torchvision import transforms#打开该图片 img_path"hymenoptera_data/val/bees/10870992_eebeeb3a12.jpg" imgImage.open(img_path) writerSummaryWriter("logs&quo…

CSS行块标签的显示方式

块级元素 标签&#xff1a;h1-h6&#xff0c;p,div,ul,ol,li,dd,dt 特点&#xff1a; &#xff08;1&#xff09;如果块级元素不设置默认宽度&#xff0c;那么该元素的宽度等于其父元素的宽度。 &#xff08;2&#xff09;所有的块级元素独占一行显示. &#xff08;3&#xff…