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代码实现)
文章目录 案例引入介绍基本介绍登场角色应用场景 案例实现案例一类图实现 案例二:借贷平台源码剖析传统方式实现分析状态修改流程类图实现 案例三:金库警报系统系统的运行逻辑伪代码传统实现方式使用状态模式 类图实现分析问题问题一问题二 总结文章说明…...
【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...
深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...
三分算法与DeepSeek辅助证明是单峰函数
前置 单峰函数有唯一的最大值,最大值左侧的数值严格单调递增,最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值,最小值左侧的数值严格单调递减,最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...
02.运算符
目录 什么是运算符 算术运算符 1.基本四则运算符 2.增量运算符 3.自增/自减运算符 关系运算符 逻辑运算符 &&:逻辑与 ||:逻辑或 !:逻辑非 短路求值 位运算符 按位与&: 按位或 | 按位取反~ …...
内窥镜检查中基于提示的息肉分割|文献速递-深度学习医疗AI最新文献
Title 题目 Prompt-based polyp segmentation during endoscopy 内窥镜检查中基于提示的息肉分割 01 文献速递介绍 以下是对这段英文内容的中文翻译: ### 胃肠道癌症的发病率呈上升趋势,且有年轻化倾向(Bray等人,2018&#x…...
Linux操作系统共享Windows操作系统的文件
目录 一、共享文件 二、挂载 一、共享文件 点击虚拟机选项-设置 点击选项,设置文件夹共享为总是启用,点击添加,可添加需要共享的文件夹 查询是否共享成功 ls /mnt/hgfs 如果显示Download(这是我共享的文件夹)&…...
MLP实战二:MLP 实现图像数字多分类
任务 实战(二):MLP 实现图像多分类 基于 mnist 数据集,建立 mlp 模型,实现 0-9 数字的十分类 task: 1、实现 mnist 数据载入,可视化图形数字; 2、完成数据预处理:图像数据维度转换与…...
