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单向同步…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...
嵌入式常见 CPU 架构
架构类型架构厂商芯片厂商典型芯片特点与应用场景PICRISC (8/16 位)MicrochipMicrochipPIC16F877A、PIC18F4550简化指令集,单周期执行;低功耗、CIP 独立外设;用于家电、小电机控制、安防面板等嵌入式场景8051CISC (8 位)Intel(原始…...
