当前位置: 首页 > news >正文

Qt之元对象系统

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

元对象系统基于三个要素:

1、QObject类为那些可以利用元对象系统的对象提供了一个基类
2、在类声明中使用Q_OBJECT宏用于启用元对象特性,比如动态属性、信号和槽。
3、元对象编译器(moc)为每个QObject子类提供必要的代码来实现元对象特性。

moc工具读取C++源文件,如果发现一个或多个包含Q_OBJECT宏的类声明,它会生成另一个C++源文件,其中包含了这些类的每个元对象的代码。这个生成的源文件被#include进入类的源文件,更常见的是被编译并链接到类的实现中。

引入这个系统的主要原因是信号和槽机制,此外它还提供了一些额外功能:

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

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

3、QObject::inherits() 函数返回一个对象是否是在 QObject 继承树内继承了指定类的实例。

4、QObject::tr() 和 QObject::trUtf8() 用于国际化的字符串翻译。

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

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

QMetaObject类包含有关Qt对象的元信息。每个在应用程序中使用的QObject子类都会创建一个QMetaObject实例,该实例存储了该QObject子类的所有元信息。此对象可通过QObject::metaObject()方法获得。
 

QMetaObject定义:

//qobjectdefs.h
struct Q_CORE_EXPORT QMetaObject{//...struct { // private dataconst QMetaObject *superdata;const QByteArrayData *stringdata;const uint *data;typedef void (*StaticMetacallFunction)(QObject *, QMetaObject::Call, int, void **);StaticMetacallFunction static_metacall;const QMetaObject * const *relatedMetaObjects;void *extradata; //reserved for future use} d;
}

QMetaObject是个结构体,没有构造函数。忽略掉所有方法声明,只剩一个结构体变量。

QMetaObject的变量会在moc_*.cpp文件中赋值:

//moc_mainwindow.cpp
QT_INIT_METAOBJECT const QMetaObject MainWindow::staticMetaObject = { {&QMainWindow::staticMetaObject,qt_meta_stringdata_MainWindow.data,qt_meta_data_MainWindow,qt_static_metacall,nullptr,nullptr
} };
变量名
const QMetaObject *superdata&QMainWindow::staticMetaObj
const QByteArrayData *stringdataqt_meta_stringdata_MainWin
const uint *dataqt_meta_data_MainWindow
StaticMetacallFunction static_metacallqt_static_metacall
const QMetaObject * const *relatedMetaObjectsnullptr
void *extradatanullptr

对于const QMetaObject *superdata = &QMainWindow::staticMetaObject;
MainWindow的staticMetaObject的superdata持有了QMainWindow的staticMetaObject,说明MainWindow可以访问QMainWindowstaticMetaObject

做个小测试:

//mainwindow.cpp
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{//...const QMetaObject *metaDta = staticMetaObject.d.superdata;while(metaDta){qDebug() << metaDta->className();metaDta = metaDta->d.superdata;}
}/*
输出结果:
QMainWindow
QWidget
QObject
*/

从这输出结果看,我们可以看出任何类的staticMetaObject都持有了父类的staticMetaObject

对于const QByteArrayData *stringdata = qt_meta_stringdata_MainWindow.data;

moc文件里找到qt_meta_stringdata_MainWindow变量:

//moc_mainwindow.cpp
static const qt_meta_stringdata_MainWindow_t qt_meta_stringdata_MainWindow = {{
QT_MOC_LITERAL(0, 0, 10) // "MainWindow"},"MainWindow"
};

qt_meta_stringdata_MainWindow是一个qt_meta_stringdata_MainWindow_t类型,这里对它进行了初始化。继续找到qt_meta_stringdata_MainWindow_t的定义:

//moc_mainwindow.cpp
struct qt_meta_stringdata_MainWindow_t {QByteArrayData data[1];char stringdata0[11];
};

也就是说stringdata的值为QT_MOC_LITERAL(0, 0, 10) // "MainWindow"

QT_MOC_LITERAL的定义:

//moc_mainwindow.cpp
#define QT_MOC_LITERAL(idx, ofs, len) \Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(len, \qptrdiff(offsetof(qt_meta_stringdata_MainWindow_t, stringdata0) + ofs \- idx * sizeof(QByteArrayData)) \)

这个宏的作用是创建一个静态的 QByteArrayData 结构体,该结构体包含了字符串字面值的元数据。再结合注释我们推断stringdata代表"MainWindow"字符串,这里似乎是保存的类名MainWindow。从变量名qt_meta_stringdata_MainWindow推断,这个变量应该就是保存的元对象相关的字符串字面量,但我们默认工程没有元对象,我们在代码中加一个signal

//mainwindow.h
signals:void sigTest();

重新编译,可以看到,qt_meta_stringdata_MainWindow变量的初始化有所改变,从注释看明显包含了我们所加信号的名称:

//moc_mainwindow.cpp
static const qt_meta_stringdata_MainWindow_t qt_meta_stringdata_MainWindow = {{
QT_MOC_LITERAL(0, 0, 10), // "MainWindow"
QT_MOC_LITERAL(1, 11, 7), // "sigTest"
QT_MOC_LITERAL(2, 19, 0) // ""},"MainWindow\0sigTest\0"
};

对于const uint *data = qt_meta_data_MainWindow;

moc文件中找到qt_meta_data_MainWindow定义,它是一个uint数组,目前还看不出它的作用。

//moc_mainwindow.cpp
static const uint qt_meta_data_MainWindow[] = {// content:8,       // revision0,       // classname0,    0, // classinfo0,    0, // methods0,    0, // properties0,    0, // enums/sets0,    0, // constructors0,       // flags0,       // signalCount0        // eod
};

对于StaticMetacallFunction static_metacall = qt_static_metacall;

moc文件里找到qt_static_metacall定义,如果是默认工程,似乎也不做什么:

//moc_mainwindow.cpp
void MainWindow::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 * const *relatedMetaObjects = nullptr;void *extradata = nullptr;暂时不讨论。

我们目前找到了staticMetaObject初始化的位置,知道它被赋值了一些数据结构,这些数据结构都和moc相关。

我们看看QMetaObject的其他成员。

//qobjectdefs.h
struct Q_CORE_EXPORT QMetaObject
{class Connection;//...
}class Q_CORE_EXPORT QMetaObject::Connection {//...
};

ConnectionQMetaObject的内部类,它代表了信号-槽的连接,那就是说我们平常使用的connect都和它相关,是个非常重要的角色。

我们可以看看我们一般使用的connect的定义:

//qobject.h
template <typename Func1, typename Func2>static inline typename std::enable_if<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::typeconnect(/*...*/){//...return connectImpl(/*...*/);}

调用了connectImpl()

//qobject.h
static QMetaObject::Connection connectImpl(/*...*/);

的确是返回了QMetaObject::Connection,由此可见Connection是信号-槽系统的关键角色,它代表了一个建立的连接。

再看看其他接口:

//qobjectdefs.h
struct Q_CORE_EXPORT QMetaObject
{//...//基本信息const char *className() const;const QMetaObject *superClass() const;bool inherits(const QMetaObject *metaObject) const Q_DECL_NOEXCEPT;//和类信息相关int classInfoOffset() const;int classInfoCount() const;int indexOfClassInfo(const char *name) const;QMetaClassInfo classInfo(int index) const;//和方法相关int methodOffset() const;int methodCount() const;int indexOfMethod(const char *method) const;QMetaMethod method(int index) const;//和枚举相关int enumeratorOffset() const;int enumeratorCount() const;int indexOfEnumerator(const char *name) const;QMetaEnum enumerator(int index) const;//和属性相关int propertyOffset() const;int propertyCount() const;int indexOfProperty(const char *name) const;QMetaProperty property(int index) const;QMetaProperty userProperty() const;//和构造器相关int constructorCount() const;int indexOfConstructor(const char *constructor) const;QMetaMethod constructor(int index) const;//和信号、槽相关int indexOfSignal(const char *signal) const;int indexOfSlot(const char *slot) const;static bool checkConnectArgs(const char *signal, const char *method);static bool checkConnectArgs(const QMetaMethod &signal,const QMetaMethod &method);static QByteArray normalizedSignature(const char *method);static QByteArray normalizedType(const char *type);//...
}

这些方法几乎提供了获取所有"元成员"信息的方式,包括构造器、方法、属性等,之所以说“元成员”,是因为被Q_INVOKABLEQ_PROPERTY等宏修饰的成员才具有"元能力"。

和信号-槽相关的接口:

//qobjectdefs.h
struct Q_CORE_EXPORT QMetaObject
{// internal index-based connectstatic Connection connect(const QObject *sender, int signal_index,const QObject *receiver, int method_index,int type = 0, int *types = nullptr);// internal index-based disconnectstatic bool disconnect(const QObject *sender, int signal_index,const QObject *receiver, int method_index);//...// internal index-based signal activationstatic void activate(QObject *sender, int signal_index, void **argv);//...
}

从注释来看,这些接口用于内部,是以索引为基础的一些方法。

接下来是很多重载或者模板的invokeMethod()

//qobjectdefs.h
struct Q_CORE_EXPORT QMetaObject
{//...invokeMethod(/*...*/);//...
}

用于调用obj的信号或者槽。

接下来是newInstance()

//qobjectdefs.h
struct Q_CORE_EXPORT QMetaObject
{//...QObject *newInstance(/*...*/);//...
}

它是用来调用构造函数的。

觉得有帮助的话,打赏一下呗。。

           

相关文章:

Qt之元对象系统

Qt的元对象系统提供了信号和槽机制&#xff08;用于对象间的通信&#xff09;、运行时类型信息和动态属性系统。 元对象系统基于三个要素&#xff1a; 1、QObject类为那些可以利用元对象系统的对象提供了一个基类。 2、在类声明中使用Q_OBJECT宏用于启用元对象特性&#xff0c…...

Provider(1)- 什么是AudioBufferProvider

什么是AudioBufferProvider&#xff1f; 顾名思义&#xff0c;Audio音频数据缓冲提供&#xff0c;就是提供音频数据的缓冲类&#xff0c;而且这个AudioBufferProvider派生出许多子类&#xff0c;每个子类有不同的用途&#xff0c;至关重要&#xff1b;那它在Android哪个地方使…...

加密与安全_密钥体系的三个核心目标之完整性解决方案

文章目录 Pre机密性完整性1. 哈希函数&#xff08;Hash Function&#xff09;定义特征常见算法应用散列函数常用场景散列函数无法解决的问题 2. 消息认证码&#xff08;MAC&#xff09;概述定义常见算法工作原理如何使用 MACMAC 的问题 不可否认性数字签名&#xff08;Digital …...

【C++】:继承[下篇](友元静态成员菱形继承菱形虚拟继承)

目录 一&#xff0c;继承与友元二&#xff0c;继承与静态成员三&#xff0c;复杂的菱形继承及菱形虚拟继承四&#xff0c;继承的总结和反思 点击跳转上一篇文章&#xff1a; 【C】&#xff1a;继承(定义&&赋值兼容转换&&作用域&&派生类的默认成员函数…...

昇思25天学习打卡营第13天|基于MindNLP+MusicGen生成自己的个性化音乐

关于MindNLP MindNLP是一个依赖昇思MindSpore向上生长的NLP&#xff08;自然语言处理&#xff09;框架&#xff0c;旨在利用MindSpore的优势特性&#xff0c;如函数式融合编程、动态图功能、数据处理引擎等&#xff0c;致力于提供高效、易用的NLP解决方案。通过全面拥抱Huggin…...

nigix的下载使用

1、官网&#xff1a;https://nginx.org/en/download.html 双击打开 nginx的默认端口是80 配置文件 默认访问页面 在目录下新建pages&#xff0c;放入图片 在浏览器中输入地址进行访问 可以在电脑中配置本地域名 Windows设置本地DNS域名解析hosts文件配置 文件地址&#xf…...

nginx+lua 实现URL重定向(根据传入的参数条件)

程序版本说明 程序版本URLnginx1.27.0https://nginx.org/download/nginx-1.27.0.tar.gzngx_devel_kitv0.3.3https://github.com/simpl/ngx_devel_kit/archive/v0.3.3.tar.gzluajitv2.1https://github.com/openresty/luajit2/archive/refs/tags/v2.1-20240626.tar.gzlua-nginx-m…...

算法学习笔记(8.4)-完全背包问题

目录 Question&#xff1a; 图例&#xff1a; 动态规划思路 2 代码实现&#xff1a; 3 空间优化&#xff1a; 代码实现&#xff1a; 下面是0-1背包和完全背包具体的例题&#xff1a; 代码实现&#xff1a; 图例&#xff1a; 空间优化代码示例 Question&#xff1a; 给定n个物品…...

C++catch (...)陈述

catch (...)陈述 例外处理可以有多个catch&#xff0c;如果catch后的小括弧里面放...&#xff0c;就表示不限型态种类的任何例外。 举例如下 #include <iostream>int main() {int i -1;try {if (i > 0) {throw 0;}throw 2.0;}catch (const int e) {std::cout <…...

Redis实践

Redis实践 使用复杂度高的命令 如果在使用Redis时&#xff0c;发现访问延迟突然增大&#xff0c;如何进行排查&#xff1f; 首先&#xff0c;第一步&#xff0c;建议你去查看一下Redis的慢日志。Redis提供了慢日志命令的统计功能&#xff0c;我们通过以下设置&#xff0c;就…...

【Lora模型推荐】Stable Diffusion创作具有玉石翡翠质感的图标设计

站长素材AI教程是站长之家旗下AI绘图教程平台 海量AI免费教程&#xff0c;每日更新干货内容 想要深入学习更多AI绘图教程&#xff0c;请访问站长素材AI教程网&#xff1a; AI教程_深度学习入门指南 - 站长素材 (chinaz.com) logo版权归各公司所有&#xff01;本笔记仅供AIGC…...

vscode 远程开发

目录 vscode 远程连接 选择 Python 环境 vscode 远程连接 按 CtrlShiftP 打开命令面板。输入并选择 Remote-SSH: Open SSH Configuration File...。选择 ~/.ssh/config 文件&#xff08;如果有多个选项&#xff09;。在打开的文件中添加或修改你的 SSH 配置。 这个可以右键…...

前端Vue组件化实践:打造灵活可维护的地址管理组件

随着前端技术的不断演进&#xff0c;复杂度和开发难度也随之上升。传统的一体化开发模式使得每次小小的修改或功能增加都可能牵一发而动全身&#xff0c;严重影响了开发效率和维护成本。组件化开发作为一种解决方案&#xff0c;通过模块化、独立化的开发方式&#xff0c;实现了…...

虚幻引擎ue5游戏运行界面白茫茫一片,怎么处理

根剧下图顺序即可调节游戏运行界面光照问题&#xff1a; 在大纲里找到post&#xff0c;然后选中它&#xff0c;找到Exposure 把最低亮度和最高亮度的0改为1即可...

《代理选择与反爬虫策略探究:如何优化网络爬虫效率与稳定性》

代理IP如何选以及常见反爬策略 为什么需要代理&#xff1f; 因为有的网站会封IP&#xff0c;用户如果没有登录&#xff0c;那IP就是身份标识&#xff0c;如果网站发现用户行为异常就非常可能封IP 什么是代理IP 就是让一个人帮你转交请求&#xff0c;帮你转交的人对面不熟&a…...

Kotlin Flow 防抖 节流

防抖和节流是针对响应跟不上触发频率这类问题的两种解决方案。 一:防抖&#xff08;debounce&#xff09;的概念&#xff1a; 防抖是指当持续触发事件时&#xff0c;一定时间段内没有再触发事件&#xff0c;事件处理函数才会执行一次&#xff0c; 如果设定时间到来之前&#x…...

Android Studio下载与安装

Android Studio下载与安装_android studio下载安装-CSDN博客...

【LC刷题】DAY24:122 55 45 1005

122. 买卖股票的最佳时机 II class Solution { public:int maxProfit(vector<int>& prices) {int result 0;for(int i 1; i < prices.size(); i ){result max(prices[i] - prices[ i - 1], 0);}return result;} };55. 跳跃游戏 link class Solution { public…...

从零开始的python学习生活2

接上封装 class Phone:__volt0.5def __keepsinglecore(self):print("让cpu以单核运行")def if5G(self):if self.__volt>1:print("5G通话已开启")else:self.__keepsinglecore()print("电量不足&#xff0c;无法使用5G通话&#xff0c;已经设置为单…...

【并发编程】进程 线程 协程

进程&#xff08;Process&#xff09;、线程&#xff08;Thread&#xff09;和协程&#xff08;Coroutine&#xff09;构成了计算机科学中实现任务并发执行的三种核心抽象机制。通常&#xff0c;为了提高程序的执行效率&#xff0c;开发者会根据应用场景和性能需求&#xff0c;…...

GLM-4.1V-9B-Base惊艳效果:3D渲染图材质/光影/构图中文分析

GLM-4.1V-9B-Base惊艳效果&#xff1a;3D渲染图材质/光影/构图中文分析 1. 视觉理解新标杆 GLM-4.1V-9B-Base作为智谱开源的视觉多模态理解模型&#xff0c;在3D渲染图分析领域展现出令人惊艳的能力。不同于常规的图片识别工具&#xff0c;这款模型能够深入理解3D渲染图中的材…...

破解Agent“半途摆烂”困局,OpenDev凭Harness架构,撕开Code Agents的工程化真相

玩过AI Agent的人&#xff0c;几乎都有过这样的崩溃时刻&#xff1a;前几轮交互里&#xff0c;它思路清晰、反应迅速&#xff0c;像个无所不能的天才&#xff0c;你说修改一段代码&#xff0c;它能精准命中漏洞&#xff1b;你让它梳理项目结构&#xff0c;它能条理分明地给出方…...

Vue3+Cesium实战:解决404报错与Webpack配置优化指南

1. 为什么你的Cesium地图总是加载失败&#xff1f; 第一次在Vue3项目里集成Cesium时&#xff0c;我也被那些莫名其妙的404报错搞得焦头烂额。明明按照文档配置了&#xff0c;地图就是不显示&#xff0c;控制台一片红。后来才发现&#xff0c;90%的问题都出在资源路径配置上。 C…...

如何快速掌握单细胞分析:CELLxGENE新手必看的3个实用技巧

如何快速掌握单细胞分析&#xff1a;CELLxGENE新手必看的3个实用技巧 【免费下载链接】cellxgene An interactive explorer for single-cell transcriptomics data 项目地址: https://gitcode.com/gh_mirrors/ce/cellxgene 你是否曾经面对海量的单细胞转录组数据感到无从…...

dupeguru重复文件查找终极指南:3种扫描模式与高效文件管理完全教程

dupeguru重复文件查找终极指南&#xff1a;3种扫描模式与高效文件管理完全教程 【免费下载链接】dupeguru Find duplicate files 项目地址: https://gitcode.com/gh_mirrors/du/dupeguru 你是否曾经因为电脑磁盘空间不足而烦恼&#xff1f;面对成千上万的文件&#xff0…...

5个宝可梦ROM定制技巧:pk3DS开源工具打造个性化游戏体验

5个宝可梦ROM定制技巧&#xff1a;pk3DS开源工具打造个性化游戏体验 【免费下载链接】pk3DS Pokmon (3DS) ROM Editor & Randomizer 项目地址: https://gitcode.com/gh_mirrors/pk/pk3DS 宝可梦游戏的重复游玩体验一直是玩家面临的核心挑战&#xff0c;如何通过技术…...

MySQL源码编译部署主从及MHA高可用集群实战

一.Mysql的源码编译1.下载安装包wget https://downloads.mysql.com/archives/get/p/23/file/mysql-boost-8.3.0.tar.gz2.源码编译# 安装编译依赖的软件包&#xff0c;包括C/C编译器(如gcc/gcc-c)、构建工具(如cmake, git, bison)和开发库(如openssl-devel, ncurses-devel) [roo…...

数据科学入门指南:10周掌握数据分析核心技能 [特殊字符]

数据科学入门指南&#xff1a;10周掌握数据分析核心技能 &#x1f680; 【免费下载链接】Data-Science-For-Beginners 10 Weeks, 20 Lessons, Data Science for All! 项目地址: https://gitcode.com/GitHub_Trending/da/Data-Science-For-Beginners 想要在数据驱动的时代…...

从一道蓝桥杯EDA赛题,聊聊平衡车硬件设计中那些‘不起眼’却关键的安全电路

平衡车硬件设计中的安全电路&#xff1a;从蓝桥杯赛题到工程实战 去年调试一款平衡车原型机时&#xff0c;我曾遇到一个诡异现象&#xff1a;每次电池快耗尽时&#xff0c;电机就会突然失控。经过三天排查&#xff0c;最终发现问题出在电源检测电路的分压电阻取值上——这个看似…...

如何构建Min浏览器插件:从零开始的可扩展架构指南

如何构建Min浏览器插件&#xff1a;从零开始的可扩展架构指南 【免费下载链接】min A fast, minimal browser that protects your privacy 项目地址: https://gitcode.com/gh_mirrors/mi/min Min浏览器作为一款注重隐私保护的轻量级浏览器&#xff0c;其插件系统为开发者…...