Qt五大核心特性之元对象系统
前言
Qt 的元对象系统(Meta-Object System)是 Qt 框架的核心之一,提供了一些 C++ 原生不具备的功能(因为在C++它们是静态的),如反射、信号槽机制、属性系统等。通过这个系统,Qt 实现了许多强大的功能,这使得它成为一个更易于使用和扩展的框架。
正文
元对象系统
1. 元对象系统的组成部分
1.1 Q_OBJECT 宏
- Q_OBJECT 是元对象系统的入口。任何需要使用元对象系统功能的类都必须包含这个宏。
- 它通常放在类的私有部分的顶部,并由 Qt 的元对象编译器(moc)处理,生成与类相关的元数据和代码。
class MyClass : public QObject {Q_OBJECTpublic:MyClass(QObject *parent = nullptr) : QObject(parent) {}signals:void mySignal();public slots:void mySlot();
};
1.2 QMetaObject
- 元对象
QMetaObject是用于描述另一个对象结构的对象,它提供了关于 QObject 类及其子类的元数据(如类名、信号、槽、属性等)。 - 可以通过调用
QObject::metaObject()来获取与对象相关的元对象。
const QMetaObject *meta = myObject->metaObject();
qDebug() << "Class name:" << meta->className();
1.3 信号和槽(Signals and Slots)
- 信号槽机制是 Qt 中的核心通信方式。信号(signal)是用来发出事件通知的,而槽(slot)是用来处理这些事件的。
signals:和slots:关键字标识了类中的信号和槽函数,信号槽的连接可以在编译时或运行时完成。
QObject::connect(sender, &SenderClass::signalName, receiver, &ReceiverClass::slotName);
1.4 属性系统(Property System)
- 属性系统使得可以通过字符串名称访问和操作对象的属性,这在 QML 和动画系统中尤其有用。
- 使用
Q_PROPERTY宏来定义属性。
class MyClass : public QObject {Q_OBJECT// 意思是value通过setValue这个函数来更新/设置这个值,在更新后发出通知信号valueChanged(int) // 当属性值发生改变时,这个信号会被发出,通知所有连接到该信号的槽函数Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)public:int value() const { return m_value; }void setValue(int value) {if (m_value == value)return;m_value = value;emit valueChanged(m_value);}signals:void valueChanged(int newValue);private:int m_value;
};
1.5 QMetaObject::invokeMethod
- 可以在运行时使用
QMetaObject::invokeMethod()来调用对象的槽函数或其它成员函数。
MyClass obj;
QMetaObject::invokeMethod(&obj, "mySlot");
2. 元对象编译器(moc)
Qt 的元对象编译器 moc 是解析带有 Q_OBJECT 宏的文件。moc 若发现一个或多个包含了 Q_OBJECT 宏的类的声明,则会生成另外一个包含了Q_OBJECT 宏实现代码的 C++源文件(该源文件通常名称为 moc_*.cpp) ,这个新的源文件要么被#include 包含到类的源文件中,要么被编译键接到类的实现中(通常是使用的此种方法)。注意:新文件不会“替换”掉旧的文件,而是与原文件一起编译
moc主要做了一下工作
- 生成一个静态的元对象实例,该实例包含类的元信息。
- 为每个信号生成一个函数,该函数可以发射该信号。
- 为类生成一个静态的成员函数,该函数可以返回静态的元对象实例。
3.反射机制
反射(Reflection)指的是程序在运行时检查和操作自身结构的能力。C++ (C++17好像支持,但是和Qt中的不同)本身不支持反射,但 Qt 通过元对象系统提供了一定程度的反射能力。这种能力主要体现在以下几个方面:
-
动态类型信息:
- 使用
QObject::metaObject()可以在运行时获取与类相关的元数据(如类名、信号、槽、属性等)。
- 使用
-
动态属性访问:
- 通过
QObject::setProperty()和QObject::property()方法,可以通过字符串名称在运行时访问和修改对象的属性。
- 通过
-
信号与槽的动态连接:
- 使用
QObject::connect()函数,可以在运行时通过字符串名称来动态连接信号和槽。这使得信号和槽的连接可以在运行时根据条件来建立或改变。
- 使用
-
动态对象创建:
- 使用
QMetaObject::newInstance()可以在运行时根据类的元对象创建新的对象实例(前提是类中有符合条件的构造函数)。
- 使用
Qt 的元对象系统通过元对象编译器(moc)生成附加的代码,允许在运行时获取类的元数据,并使用这些元数据实现类似反射的功能。这种机制在实现动态特性、插件系统和QML绑定等功能时非常有用。
4. 元对象系统的使用
元对象系统的使用需要满足三个条件
- 该类必须继承自
QObject或者继承自继承QObject类的子类 - 该类在声明
Q_OBJECT这个宏时,必须在私有区域进行声明 - 元对象编译器(moc)为每个
QObject的子类,提供了实现员特性所必须的代码
MyClass.h
#ifndef MYCLASS_H
#define MYCLASS_H#include <QObject>
#include <QDebug>// MyClass 是一个示例类,展示了 Qt 元对象系统的使用
class MyClass : public QObject {Q_OBJECT// 定义一个属性 "value",可以通过 getter (value) 和 setter (setValue) 访问,// 当属性值发生变化时发出信号 valueChangedQ_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)public:explicit MyClass(QObject *parent = nullptr);// 属性的 getter 函数int value() const;// 属性的 setter 函数void setValue(int newValue);signals:// 当属性值发生变化时发出的信号void valueChanged(int newValue);public slots:// 一个槽函数,用于打印当前属性值void printValue();private:int m_value; // 用于存储属性值的成员变量
};#endif // MYCLASS_H
MyClass.cpp
#include "MyClass.h"// 构造函数,初始化属性值为 0
MyClass::MyClass(QObject *parent) : QObject(parent), m_value(0) {}// getter 函数,返回当前的属性值
int MyClass::value() const {return m_value;
}// setter 函数,设置属性值,并发出 valueChanged 信号(如果值发生变化)
void MyClass::setValue(int newValue) {if (m_value != newValue) {m_value = newValue;emit valueChanged(m_value);}
}// 槽函数,打印当前属性值
void MyClass::printValue() {qDebug() << "The value is:" << m_value;
}
main.cpp
#include <QCoreApplication>
#include <QMetaObject>
#include <QMetaProperty>
#include <QMetaMethod>
#include "MyClass.h"int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);// 动态创建 MyClass 对象QObject *obj = QMetaObject::newInstance(MyClass::staticMetaObject);// 检查对象是否创建成功if (!obj) {qDebug() << "Failed to create the object!";return -1;}// 获取对象的元对象信息const QMetaObject *metaObj = obj->metaObject();qDebug() << "Class Name:" << metaObj->className();// 动态访问和修改属性int propertyIndex = metaObj->indexOfProperty("value");if (propertyIndex != -1) {obj->setProperty("value", 42); // 设置属性值qDebug() << "Property 'value':" << obj->property("value").toInt(); // 获取属性值}// 动态连接信号和槽int signalIndex = metaObj->indexOfSignal("valueChanged(int)");int slotIndex = metaObj->indexOfSlot("printValue()");if (signalIndex != -1 && slotIndex != -1) {QMetaObject::connect(obj, signalIndex, obj, slotIndex);}// 修改属性值,这将触发 valueChanged 信号,并调用 printValue 槽函数obj->setProperty("value", 100);// 清理动态创建的对象delete obj;return a.exec();
}
代码解释
MyClass.h
Q_OBJECT: 必须放在类的定义中,用于启用 Qt 的元对象系统。Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged): 定义一个名为value的属性,指定了 getter (value)、setter (setValue) 和属性变化时发出的信号 (valueChanged)。signals:: 定义信号valueChanged,当value属性发生变化时发出。public slots:: 定义槽函数printValue,用于打印属性值。
MyClass.cpp
MyClass::MyClass(QObject *parent): 构造函数,初始化m_value为 0。value(): 返回当前的m_value。setValue(int newValue): 设置m_value的值,并在值发生变化时发出valueChanged信号。printValue(): 打印当前的m_value。
main.cpp
QMetaObject::newInstance(MyClass::staticMetaObject): 动态创建MyClass的实例。MyClass::staticMetaObject提供了类的元对象信息。metaObject()->className(): 获取并打印类名。metaObject()->indexOfProperty("value"): 获取属性value的索引。通过索引动态设置和获取属性值。QMetaObject::connect(): 动态连接信号valueChanged(int)和槽printValue()。obj->setProperty("value", 100): 修改属性值,触发valueChanged信号,进而调用printValue槽函数。
注意:若定义了QObject类的派生类,并进行了构建,在这之后再添加 Q_OBJECT 宏,则此时
必须执行一次 qmake 命令(“构建”>“执行 qmake”),否则 moc 不能生成代码。
相关文章:
Qt五大核心特性之元对象系统
前言 Qt 的元对象系统(Meta-Object System)是 Qt 框架的核心之一,提供了一些 C 原生不具备的功能(因为在C它们是静态的),如反射、信号槽机制、属性系统等。通过这个系统,Qt 实现了许多强大的功能,这使得它…...
开放式耳机伤耳朵吗?开放式耳机在一定程度上保护我们的耳朵
开放式耳机通常被认为对耳朵的伤害较小,因为它们不需要插入耳道,从而减少了耳道内的压力和潜在的感染风险。与传统入耳式耳机相比,开放式耳机允许耳朵自然通风,减少耳道内的湿气和热量积聚,这有助于保持耳朵的健康。 然…...
JAVA打车小程序APP打车顺风车滴滴车跑腿源码微信小程序打车系统源码
🚗💨打车、顺风车、滴滴车&跑腿系统,一键解决出行生活难题! 一、出行新选择,打车从此不再难 忙碌的生活节奏,让我们常常需要快速、便捷的出行方式。打车、顺风车、滴滴车系统,正是为了满足…...
批量智慧:揭秘机器学习中的批量大小
标题:批量智慧:揭秘机器学习中的批量大小 机器学习是人工智能的一个分支,它使得计算机能够从数据中学习并做出决策或预测。在机器学习的过程中,批量大小(Batch Size)是一个至关重要的超参数,它…...
苹果Vision Pro生态发展:现状、挑战与未来展望
苹果公司以其创新技术和强大的生态系统闻名于世。在最近的财报会议上,CEO蒂姆库克分享了Vision Pro平台的最新进展,引发了业界的广泛关注。本文将深入探讨Vision Pro生态的现状、面临的挑战以及与其他XR平台的对比分析。 一、Vision Pro生态现状 据库克介绍,Vision Pro平台…...
湖南第一师范学院来访炼石,推动密码与数据安全合作
2024年8月11日,为进一步加强交流与合作,深入探讨校企产学研合作,湖南第一师范学院计算机学院院长杨恒伏一行莅临炼石调研指导。湖南第一师范学院计算机学院院长杨恒伏、网络空间安全系主任周聪等专家领导出席。炼石网络创始人兼CEO白小勇对湖…...
全面解析ETL:数据仓库架构中的关键处理过程
目录 一、数据仓库架构中的ETL 二、数据抽取 (1)逻辑抽取 (2)物理抽取 (3)变化数据捕获 三、数据转换 四、数据装载 (1)提高装载效率 (2)处理装载失败 五、ET…...
keepalived的介绍与配置
Keepalived是一个轻量级别的高可用解决方案,同时也是一个免费开源的、用C编写的类似于layer3, 4 & 7(也有说法认为是layer3, 4 & 5)交换机制的软件,主要提供负载均衡和高可用服务。它自动完成检测服务器的状态、故障隔离和…...
二叉树概念与使用
文章目录 一、作用二、二叉树概念特征2.1二叉树概念补充2.1.1度2.1.2深度2.1.3若规定根节点的层数为1,则深度为h的二叉树的最大结点数是2^h-1个结点 三、使用2.1二叉树存储,检索,插入项目 四、 二叉树检索的时间复杂度1. 普通二叉树2. 二叉搜…...
MongoDB 在 Java 中的使用教程
目录 MongoDB 简介环境准备使用 Java 连接 MongoDB基本 CRUD 操作复杂查询操作索引和性能优化事务管理总结 1. MongoDB 简介 MongoDB 是一个基于分布式文件存储的 NoSQL 数据库系统。它以文档(JSON 形式)存储数据,具有高扩展性和灵活的数据…...
微前端架构下的配置管理:策略、实现与最佳实践
微前端架构通过将一个大型前端应用拆分为多个小型、自治的子应用,提升了开发效率和应用的可维护性。然而,随着应用规模的扩大和子应用数量的增加,配置管理变得日益复杂。本文将详细介绍在微前端架构下实现应用配置管理的策略、实现方法和最佳…...
React Native中好用的UI组件库
文章目录 前言1.React Native ElementsStar数超24K地址 2.React Native UI KittenStar数超20K地址 3.NativeBaseStar数超20K地址 前言 下面是React Native中一些常用的UI库 1.React Native Elements Star数超24K 官方介绍 React Native Elements 的目标是提供一套用于在 Rea…...
WebSocket 快速入门
WebSocket是什么 WebSocket 是基于 TCP 的一种新的应用层网络协议。它实现了浏览器与服务器全双工通信,即允许服务器主动发送信息给客户端。因此,在 WebSocket 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性…...
MySQL中的存储文件和IO机制详细解析
MySQL中的存储文件和IO机制详细解析 一、引言 MySQL作为广泛使用的关系型数据库管理系统,凭借其高性能和稳定性在各大应用中扮演了关键角色。在实际应用中,数据库需要对大量数据进行存储、检索、更新等操作。这些操作离不开底层的文件存储系统…...
复习之 java 锁
裁员在家,没有面试机会,整理整理面试知识点吧! 不得不知道的java 锁 Java 中,提供了两种方式来实现同步互斥访问(也就是锁):synchronized 和 Lock 多线程编程中,有可能会出现多个线…...
数据结构与算法 - 图
一、概念 图是有顶点(vertex)和边(edge)组成的数据结构,例如 该图有4个顶点:A、B、C、D以及四条有向边,有向图中,边是单向的。 1. 有向图 VS 无向图 如果是无向图,那么…...
白骑士的HTML教学基础篇 1.1 HTML简介
在现代互联网的世界里,HTML(HyperText Markup Language)是所有网页的基础语言。无论是简约的个人博客还是复杂的商业网站,HTML都扮演着不可或缺的角色。掌握HTML是学习前端开发的第一步,这不仅能够帮助你构建静态网页&…...
c语言基础知识学习
1. C 语言简介 定义:C 语言是一种过程式编程语言,设计用于系统编程和应用程序开发。特点:高效、灵活、接近硬件,支持指针和内存操作。 1. 基本语法 程序结构: C 语言程序由函数组成,main 函数是程序的入口…...
Qt/QML学习-Dial
QML学习 Dial例程视频讲解代码 main.qml import QtQuick 2.15 import QtQuick.Window 2.15 import QtQuick.Controls 2.15Window {width: 640height: 480visible: truetitle: qsTr("Hello World")Dial {anchors.fill: parentid: dial// 设置旋钮的范围from: 0to: …...
达梦数据库系列—48.DMHS实现Mysql到DM8的同步
目录 DMHS实现Mysql到DM8的同步 1、准备介质 2、安装 3、准备源端Mysql和目标端DM8 软件安装 数据库创建 打开归档 开启附加日志 创建辅助表 Mysql客户端驱动 Mysql端安装ODBC 检查依赖包 创建连接用户 创建测试表 4、同步配置 修改服务配置 Mysql到Dm单向同步…...
AI-调查研究-01-正念冥想有用吗?对健康的影响及科学指南
点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) 目前2025年06月05日更新到: AI炼丹日志-28 - Aud…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...
SiFli 52把Imagie图片,Font字体资源放在指定位置,编译成指定img.bin和font.bin的问题
分区配置 (ptab.json) img 属性介绍: img 属性指定分区存放的 image 名称,指定的 image 名称必须是当前工程生成的 binary 。 如果 binary 有多个文件,则以 proj_name:binary_name 格式指定文件名, proj_name 为工程 名&…...
vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
Python竞赛环境搭建全攻略
Python环境搭建竞赛技术文章大纲 竞赛背景与意义 竞赛的目的与价值Python在竞赛中的应用场景环境搭建对竞赛效率的影响 竞赛环境需求分析 常见竞赛类型(算法、数据分析、机器学习等)不同竞赛对Python版本及库的要求硬件与操作系统的兼容性问题 Pyth…...
基于单片机的宠物屋智能系统设计与实现(论文+源码)
本设计基于单片机的宠物屋智能系统核心是实现对宠物生活环境及状态的智能管理。系统以单片机为中枢,连接红外测温传感器,可实时精准捕捉宠物体温变化,以便及时发现健康异常;水位检测传感器时刻监测饮用水余量,防止宠物…...
python打卡day49@浙大疏锦行
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 一、通道注意力模块复习 & CBAM实现 import torch import torch.nn as nnclass CBAM(nn.Module):def __init__…...
