Qt 对象序列化/反序列化
阅读本文大概需要 3 分钟
背景
日常开发过程中,避免不了对象序列化和反序列化,如果你使用 Qt 进行开发,那么有一种方法实现起来非常简单和容易。
实现
我们知道 Qt 的元对象系统非常强大,基于此属性我们可以实现对象的序列化和反序列化操作。
比如有一个学生类,包含以下几个字段:学号、姓名、性别、出生日期等,定义如下类结构:
class DStudent : public QObject
{Q_OBJECTQ_PROPERTY(QString name READ name WRITE setName)Q_PROPERTY(QString number READ number WRITE setNumber)Q_PROPERTY(QString sex READ sex WRITE setSex)Q_PROPERTY(QDateTime birthday READ birthday WRITE setBirthda)
public:explicit DStudent(QObject *parent = nullptr);QString name() const;void setName(const QString &newName);QString number() const;void setNumber(const QString &newNumber);QString sex() const;void setSex(const QString &newSex);QDateTime birthday() const;void setBirthda(const QDateTime &newBirthday);//...
需要增加那些字段,只需要在上述属性位置继续追加即可,通过把需要反射的字段定义成属性,我们就可以遍历该类的元对象,进而获取其中的属性信息。
序列化 Json
QJsonObject DStudent::toJson()
{QJsonObject jsObj = KJsonHelp::object2Json(this);return jsObj;
}
bool DStudent::fromJson(const QJsonObject &jsObj)
{return KJsonHelp::json2Object(jsObj, this);
}
核心代码封装到工具类中,方便其它地方调用,详细实现如下:
QJsonObject KJsonHelp::object2Json(QObject *object)
{QJsonObject jsObj;if(nullptr == object){return jsObj;}const QMetaObject *pMetaObj = object->metaObject();for(int i = 0; i < pMetaObj->propertyCount(); i++){auto proName = pMetaObj->property(i).name();jsObj.insert(proName, QJsonValue::fromVariant(object->property(proName)));}if(jsObj.contains("objectName")){jsObj.remove("objectName");}return jsObj;
}bool KJsonHelp::json2Object(const QJsonObject &jsObj, QObject *object)
{if (jsObj.isEmpty() || nullptr == object){return false;}QStringList list;const QMetaObject *pMetaObj = object->metaObject();for(int i = 0; i < pMetaObj->propertyCount(); i++){list << pMetaObj->property(i).name();}QStringList jsonKeys = jsObj.keys();foreach(const QString &proName ,list){if(!jsonKeys.contains(proName) || jsObj.value(proName).isNull()){continue;}object->setProperty(proName.toLocal8Bit().data(), jsObj.value(proName));}return true;
}
任意一个继承 QObject的对象都可以获取到它的元对象,接着可以获取到属性个数,然后挨个进行遍历即可。
如果想序列化到其他格式的,比如XML,在上述方法中根据 XML 规则生成即可,这个不是本文的重点。
一些坑和注意点
当然了并不是所有的类型都支持这种方式自动生成字段的,一些特殊类型或者自定义的类需要自己特殊去实现。
我们可以在上述学生类中,继续添加新的测试属性字段,来看看输出的结果:
// custome typeQ_PROPERTY(DScore sScore READ sScore WRITE setSScore)// test other typeQ_PROPERTY(int testInt READ testInt WRITE setTestInt)Q_PROPERTY(bool testBool READ testBool WRITE setTestBool)Q_PROPERTY(double testDouble READ testDouble WRITE setTestDouble)Q_PROPERTY(char testChar READ testChar WRITE setTestChar)Q_PROPERTY(QUrl testUrl READ testUrl WRITE setTestUrl)Q_PROPERTY(QVariant testV READ testV WRITE setTestV)Q_PROPERTY(QStringList testStringList READ testStringList WRITE setTestStringList)Q_PROPERTY(QRect testRect READ testRect WRITE setTestRect)Q_PROPERTY(QSize testSize READ testSize WRITE setTestSize)Q_PROPERTY(QPoint testPoint READ testPoint WRITE setTestPoint)Q_PROPERTY(QList<int> testIntList READ testIntList WRITE setTestIntList)Q_PROPERTY(QList<QString> testListString READ testListString WRITE setTestListString)
打印输出:
qRegisterMetaType<DScore>("DScore");DStudent st;st.setName(QStringLiteral("法外狂徒张三"));st.setNumber("123456789");st.setSex(QStringLiteral("男"));st.setBirthda(QDateTime::currentDateTime());// test other typest.setTestInt(10);st.setTestBool(true);st.setTestV(12);st.setTestDouble(12.121212);st.setTestChar('k'); //->stringst.setTestUrl(QUrl("http://kevinlq.com/")); // -> stringst.setTestStringList(QStringList() << "stringList1" << "stringList2");st.setTestRect(QRect(10,10,10,10)); // nullst.setTestSize(QSize(10,10)); // nullst.setTestPoint(QPoint(10, 10)); // nullst.setTestIntList({11, 12}); // nullst.setTestListString({"kevinlq", "devstone"}); // nullDScore score;score.setName("computer");score.setNumber("001");st.setSScore(score); // nullqDebug() << "st:" << st.toJson();
st: QJsonObject({"birthday":"2023-08-05T19:33:14.815","name":"法外狂徒张三","number":"123456789","sScore":null,"sex":"男","testBool":true,"testChar":"k","testDouble":12.121212,"testInt":10,"testIntList":null,"testListString":null,"testPoint":null,"testRect":null,"testSize":null,"testStringList":["stringList1","stringList2"],"testUrl":"http://kevinlq.com/","testV":12})
可以看到很多字段的值是 null,出现这种问题表示这个类型目前无法直接自动生成,如果你缺失需要这种结构,那么需要自行在序列化函数中进行特殊处理,比如自定义的类型处理:
QJsonObject DStudent::toJson()
{QJsonObject jsObj = KJsonHelp::object2Json(this);jsObj.insert("sScore", m_sScore.toJson());return jsObj;
}
上述对定义的课程类,进行了特殊处理,再次编译后,输出的结果如下:
{"birthday": "2023-08-05T23:27:00.757","name": "法外狂徒张三","number": "123456789","sScore": {"name": "computer","number": "001"}
}
可以看到正常输出了我们需要的类型,其他类型可以照葫芦画瓢。
进阶
是不是发现问题了,随着你的类属性字段越来越多,手写这么多字段肯定非常累,能否自动生成这些重复的代码呢,答案是可以的,结合前面的文章,就可以编写一份更加紧凑的代码了,详细见这里 http://kevinlq.com/2023/01/16/generateProperty/
总结
序列化其实有很应用场景,以下是工作站经常使用的小 case:
- 持久化保存类对象,及保存数据到本地磁盘;
- socket 传输数据,需要把 json/xml/other 类型转为对象,用对象进行业务处理;
- 数据库操作:从 db 中读取出来的值序列化成对象,方便业务进行处理(使用 ORM 框架例外)
- 和界面交互,比如界面使用 QML 编写,那么大部分超场景会使用到 JSON。
- 其他:待补充……
参考文档
- c++自动生成get/set方法
相关文章:
Qt 对象序列化/反序列化
阅读本文大概需要 3 分钟 背景 日常开发过程中,避免不了对象序列化和反序列化,如果你使用 Qt 进行开发,那么有一种方法实现起来非常简单和容易。 实现 我们知道 Qt 的元对象系统非常强大,基于此属性我们可以实现对象的序列化和…...
从零学算法(非官方题库)
输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构) B是A的子结构, 即 A中有出现和B相同的结构和节点值。 例如: 给定的树 A:3/ \4 5/ \1 2给定的树 B:4 / 1返回 true,因为 B 与 A 的一个子树拥有相…...
Java # JVM内存管理
一、运行时数据区域 程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区、运行时常量池、直接内存 二、HotSpot虚拟机对象 对象创建: 引用检查类加载检查分配内存空间:指针碰撞、空闲列表分配空间初始化对象信息设置(对象头内࿰…...
大疆第二批笔试复盘
大疆笔试复盘(8-14) 笔试时候的状态和下来复盘的感觉完全不一样,笔试时脑子是懵的。 (1)输出无重复三位数 题目描述 从 { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 } \left \{ 1,2,3,4,5,6,7,8,9 \right \...
【Linux】磁盘或内存 占用比较高要怎么排
当 Linux 磁盘空间满了时 请注意,在进行任何删除操作之前,请确保你知道哪些文件可以安全删除,并备份重要文件,以免意外丢失数据。当 Linux 磁盘空间满了时,可以按照以下步骤进行排查: 检查磁盘使用情况&…...
解决xss转义导致转码的问题
一、xss简介 人们经常将跨站脚本攻击(Cross Site Scripting)缩写为CSS,但这会与层叠样式表(Cascading Style Sheets,CSS)的缩写混淆。因此,有人将跨站脚本攻击缩写为XSS。跨站脚本攻击ÿ…...
numba 入门示例
一维向量求和: C A B 在有nv 近几年gpu的ubuntu 机器上, 环境预备: conda create -name numba_cuda_python3.10 python3.10 conda activate numba_cuda_python3.10conda install numba conda install cudatoolkit conda install -c nvi…...
BUUCTF 还原大师 1
题目描述: 我们得到了一串神秘字符串:TASC?O3RJMV?WDJKX?ZM,问号部分是未知大写字母,为了确定这个神秘字符串,我们通过了其他途径获得了这个字串的32位MD5码。但是我们获得它的32位MD5码也是残缺不全,E903???4D…...
自定义hook之首页数据请求动作封装 hooks
本例子实现了自定义hook之首页数据请求动作封装 hooks,具体代码如下 export type OrganData {dis: Array<{ disease: string; id: number }>;is_delete: number;name: string;organ_id: number;parent_id: number;sort: number; }; export type SwiperData …...
2023上半年京东手机行业品牌销售排行榜(京东数据平台)
后疫情时代,不少行业都迎来消费复苏,我国智能手机市场在今年上半年也实现温和的复苏,手机市场的出货量回暖。 根据鲸参谋平台的数据显示,2023年上半年,京东平台上手机的销量为2830万,环比增长约4%…...
lodash之cloneDeep()源码阅读笔记
lodash之cloneDeep()源码阅读笔记 基本上都在写业务代码,没有机会写库,还是想了解一下lodash的库源码是怎么样的,平时用的最多的就是cloneDeep()方法了,终于有空详细看看其中的源码。 本文基于lodash5.0.0版本的源码进行阅读。 /…...
算法模版,今天开始背
二分查找算法 int left_bound(int[] nums, int target) {int left 0, right nums.length - 1;// 搜索区间为 [left, right]while (left < right) {int mid left (right - left) / 2;if (nums[mid] < target) {// 搜索区间变为 [mid1, right]left mid 1;} else if …...
新的 Python URL 解析漏洞可能导致命令执行攻击
Python URL 解析函数中的一个高严重性安全漏洞已被披露,该漏洞可绕过 blocklist 实现的域或协议过滤方法,导致任意文件读取和命令执行。 CERT 协调中心(CERT/CC)在周五的一份公告中说:当整个 URL 都以空白字符开头时&…...
react项目做的h5页面加载缓慢优化(3s优化到0.6s)
打包到生产环境时去掉SOURCEMAP 禁用生成 Source Map 是一种权衡,可以根据项目的实际需求和优化目标来决定是否禁用。如果您对调试需求不是特别强烈,可以考虑在生产构建中禁用 Source Map 以获取更好的性能。但如果需要保留调试能力,可以在生…...
如何修复损坏的DOC和DOCX格式Word文件?
我们日常办公中,经常用到Word文档。但是有时会遇到word文件损坏、无法打开的情况。这时该怎么办?接着往下看,小编在这里就给大家带来最简单的Word文件修复方法! 很多时候DOC和DOCX Word文件会无缘无故的损坏无法打开,一…...
UI设计师个人工作感悟5篇
UI设计师个人工作感悟一 工作一年了,结合我自身谈谈UI设计的重要性。现在主流的论坛建站程序有两种 Phpwind 和Discuz(Phpwind被阿里巴巴收购 Discuz被腾讯收购这两个论坛程序都是开源免费的),利用这两种程序我都分别建立过论坛,我第一次用的…...
Java堆、栈、内存的知识
在JAVA中,有六个不同的地方可以存储数据: 1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制. 2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆&…...
tp6 RabbitMQ
1、composer 安装 AMQP 扩展 composer require php-amqplib/php-amqplib 2、RabbitMQ 配置 在 config 目录下创建 rabbitmq.php 文件 <?php return [host>,port>5672,user>,password>,vhost>,exchange_name > ,queue_name > ,route_key > ,cons…...
java Spring Boot yml多环境拆分文件管理优化
上文 java Spring Boot yml多环境配置 我们讲了多环境开发 但这种东西都放在一起 还是非常容易暴露信息的 并且对维护来讲 也不是非常的友好 这里 我们在resources下创建三个文件 分别叫 application-pro.yml application-dev.yml application-test.yml 我们直接将三个环境 转…...
【设计模式——学习笔记】23种设计模式——状态模式State(原理讲解+应用场景介绍+案例介绍+Java代码实现)
文章目录 案例引入介绍基本介绍登场角色应用场景 案例实现案例一类图实现 案例二:借贷平台源码剖析传统方式实现分析状态修改流程类图实现 案例三:金库警报系统系统的运行逻辑伪代码传统实现方式使用状态模式 类图实现分析问题问题一问题二 总结文章说明…...
EXE Ver 适用于 未安装Python 以及包的Windows OS
上图~EXE Ver END...
python confluence
# Python Confluence:让团队知识流动起来 在团队协作中,知识管理常常是个令人头疼的问题。文档散落在各处,版本混乱,新成员找不到关键信息,老员工的经验难以沉淀。如果你也遇到过这些问题,那么Python Conf…...
安装The Agency后Opencode启动报错:Failed to parse YAML frontmatter: incomplete explicit mapping pair
报错:opencode Failed to parse frontmatter in /home/skywalk/opencodework/.opencode/agent/zk-steward.md: Failed to parse YAML frontmatter: incomplete explicit mapping pair; a key node is missed; or followed by a non-tabulated empty line at line 3,…...
SparkSQL临时表实战:4种高效创建方式与应用场景解析
1. SparkSQL临时表基础与应用场景 临时表是SparkSQL中处理数据的重要工具,它允许我们在数据处理过程中暂存中间结果,避免重复计算。我在实际项目中经常遇到需要多次引用同一数据集的情况,这时候临时表就能大显身手。比如做数据清洗时…...
ROS teb_local_planner实战:从源码编译到多机编队避障调优
1. 为什么选择TEB算法优化多机编队避障? 在狭窄环境中实现多机器人编队移动,就像让一群人在拥挤的走廊里保持队形行走。传统DWA算法就像个固执的领队,只愿意前进不愿后退,遇到死胡同就卡住。而TEB(Timed Elastic Band&…...
2026.04.02随记
1、DL1、反向传播(backward propagation):是计算网络参数梯度的方法,用链式法则,从输出层到输入层遍历,算出每个参数该怎么改。反向传播中每一个记录的梯度都是该函数的导数。梯度下降不等于反向传播&#…...
气象、水文、区域气候--从零搭建 WRF 实验室:Linux 编译 + Python 绘图 + 下垫面改造一站式技术
做气象、水文、气候、环境、地理遥感等领域的科研人,是不是都逃不过这些噩梦:编译地狱:Linux 环境下 NetCDF、MPI、WRF 编译报错满天飞,compile.log里的 Error 看不懂,卡了一周连第一步都跑不通环境混乱:Fo…...
从广播风暴到安全隔离:用Wireshark抓包分析VLAN工作原理(实验对比版)
从广播风暴到安全隔离:用Wireshark抓包分析VLAN工作原理(实验对比版) 当你按下回车键发送一个广播消息时,这个数据包会像野火一样蔓延到整个网络——至少在没有VLAN的传统以太网中是这样。我曾亲眼见证过一个简单的ARP请求如何拖垮…...
查重 AIGC 率双杀!Paperxie AI:从红标警告到绿码通关的终极方案
paperxie-免费查重复率aigc检测/开题报告/毕业论文/智能排版/文献综述/AIPPThttps://www.paperxie.cn/weight?type1https://www.paperxie.cn/weight?type1 深夜的宿舍里,本科生小张盯着电脑屏幕上的检测报告,心脏跟着数据狂跳 —— 知网查重率 42%&…...
SLIC超像素分割实战:从原理到OpenCV代码实现(附完整示例)
SLIC超像素分割实战:从原理到OpenCV代码实现(附完整示例) 在计算机视觉领域,图像分割一直是个基础而关键的课题。想象一下,当你需要让计算机理解一张照片时,直接处理数百万个像素显然效率太低——这就好比…...
