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代码实现)
文章目录 案例引入介绍基本介绍登场角色应用场景 案例实现案例一类图实现 案例二:借贷平台源码剖析传统方式实现分析状态修改流程类图实现 案例三:金库警报系统系统的运行逻辑伪代码传统实现方式使用状态模式 类图实现分析问题问题一问题二 总结文章说明…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
设计模式和设计原则回顾
设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件,用于在原生应用中加载 HTML 页面: 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...
提升移动端网页调试效率:WebDebugX 与常见工具组合实践
在日常移动端开发中,网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时,开发者迫切需要一套高效、可靠且跨平台的调试方案。过去,我们或多或少使用过 Chrome DevTools、Remote Debug…...
Vue 模板语句的数据来源
🧩 Vue 模板语句的数据来源:全方位解析 Vue 模板(<template> 部分)中的表达式、指令绑定(如 v-bind, v-on)和插值({{ }})都在一个特定的作用域内求值。这个作用域由当前 组件…...
前端调试HTTP状态码
1xx(信息类状态码) 这类状态码表示临时响应,需要客户端继续处理请求。 100 Continue 服务器已收到请求的初始部分,客户端应继续发送剩余部分。 2xx(成功类状态码) 表示请求已成功被服务器接收、理解并处…...

路由基础-路由表
本篇将会向读者介绍路由的基本概念。 前言 在一个典型的数据通信网络中,往往存在多个不同的IP网段,数据在不同的IP网段之间交互是需要借助三层设备的,这些设备具备路由能力,能够实现数据的跨网段转发。 路由是数据通信网络中最基…...