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

简单实现QT对象的[json]序列化与反序列化

简单实现QT对象的[json]序列化与反序列化

  • 简介
  • 应用场景
  • qt元对象系统
  • 思路
  • 实现
  • 使用方式
  • 题外话

简介

众所周知json作为一种轻量级的数据交换格式,在开发中被广泛应用。因此如何方便的将对象数据转为json格式和从json格式中加载数据到对象中就变得尤为重要。
在python类动态语言中,我们可以很方便的使用json.dumps()和json.load()完成json数据的生成和加载。但是在QT中就不能非常方便的转换。
因此本文将使用QT中的元对象系统实现简单的json数据转换和加载

应用场景

假如现在需要开发一个系统,采用c/s架构,使用json格式作为前后端的数据交互协议,那么针对每个接口,所需要交互的数据都需要转换为json或者从json中获取。
举个栗子:
现有个需要,需要根据用户id获取用户的详细信息,由客户端发起请求,服务端返回数据

//客户端
//1.定义数据结构体
struct requestUserInfo
{int id = -1;
};
struct responseUserInfo
{QString name;int age;//....
};
//2.定义数据
requestUserInfo _data;
_data.id = 1;
//3.转换为json数据,转换过程就不展示了
QByteArray _requestData = "xxx";
auto _result = network.sendData(_requestData);
//4.将结果转换为responseUserInfo,转换过程就不详细描述了
responseUserInfo _responseData;
//5.显示详细信息
//.....

在这个过程中,可以很清楚的看到,第3步和第4步的转换和解析过程将会耗费大量的事件书写很多冗余的代码,如果能够很方便的将结构体(对象)转换为json 和从json转换为结构体。代码的书写将会变得简洁而高效。

qt元对象系统

在此之前我们需要先了解一下qt的元对象系统是什么,ai回答如下:

  • 信号和槽机制:Qt的元对象系统支持信号和槽之间的通信,这是Qt中对象间通信的主要方式。信号是由对象发出的通知,告知发生了某个事件,而槽是响应这些信号的函数。这种机制替代了传统的回调函数,使得对象间的协作更加简单和直观
  • 运行时类型信息:元对象系统提供了运行时类型信息(RTTI),允许程序在运行时查询对象的类型。这包括获取类的名称、父类的名称、类中信号和槽的数量和名称等
  • 动态属性系统:Qt的元对象系统支持动态属性,这意味着可以在运行时添加、修改或删除对象的属性。这些属性可以用于Qt Designer工具中,也可以在QML中使用
  • 继承和多态:Qt的元对象系统支持面向对象编程中的继承和多态特性。通过使用Q_OBJECT宏和元对象编译器(MOC),Qt能够为继承自QObject的类生成额外的代码,以支持信号和槽、属性等元对象特性
  • 元对象编译器(MOC):为了使用元对象系统,需要在类定义中包含Q_OBJECT宏,然后使用MOC编译器生成额外的代码来支持元对象特性。MOC是Qt构建过程中自动调用的,它解析C++头文件,并为包含Q_OBJECT宏的类生成运行时所需的代码
  • 对象树和所有权:Qt使用对象树来组织和管理所有的QObject及其子类的对象。当一个对象被创建并指定另一个对象为其父对象时,它会被添加到父对象的孩子列表中。当父对象被销毁时,子对象也会自动被销毁,这有助于简化内存管理并减少内存泄漏的风险
  • 自定义属性:Qt提供了基于元对象系统的自定义属性机制,允许开发者定义自己的属性,并在Qt Designer和QML中使用这些属性。这些属性可以通过Q_PROPERTY宏来声明,并可以设置为动态属性

总之,继承至QObject的子类,在运行时可以通过qt的元对象系统获取对象的名称和属性信息,并且可以自定义信息,其他的特性不在本文讨论的范围中,如果大家感兴趣,后续可以专门写篇文章介绍。

思路

上面提到Qt的元对象系统可以在运行时获取对象的属性,并且支持自定义属性,所以我们就需要借助元对象的这两个属性来完成对象的序列化和反序列化。
在利用qt的元对象特性,利用QMetaObject类获取属性名称和属性值,在转换为json格式,同理从json格式加载时,也可以利用QMetaObject类向属性中写入数据。

实现

通过上述的原理,我实现了简单的转换和加载函数,都包含在一个头文件中,使用时也只需要包含头文件即可,还是很方便。
jsonHelper.h

#include <QObject>
#include <QJsonObject>
#include <QMetaObject>
#include <QMetaProperty>
#include <QMetaMethod>
#include <QJsonValue>#define READ_WRITE_VALUE(_type,val) 		\
_type get_##val() const {return val;}			\
void set_##val(const _type& _t){val = _t;}#define READ_WRITE_VALUE_TEMPLATE(val) \
auto get_##val() const -> decltype(val) { return val; } \
void set_##val(const decltype(val)& _t) { val = _t; }#define READ_FUNC_NAME(_name) 	get_##_name
#define WRITE_FUNC_NAME(_name) 	set_##_name#define READ_OBJECT(_name)	Q_INVOKABLE QJsonObject read_##_name(){return objDump(&_name);}#define WRITE_OBJECT(_name)	Q_INVOKABLE void set_##_name(const QJsonObject& _jsonObj){ objLoad(_jsonObj,&_name);}inline QJsonObject objDump(QObject* _obj)
{QJsonObject _jsonObj;auto _meatObj = _obj->metaObject();for(int i = _meatObj->propertyOffset(); i < _meatObj->propertyCount(); i++){auto _property = _meatObj->property(i);auto _type = _property.type();if(_type < QVariant::UserType){_jsonObj[_property.name()] = _property.read(_obj).toJsonValue();}}for(int i = _meatObj->methodOffset(); i < _meatObj->methodCount(); i++){auto _meth = _meatObj->method(i);if(_meth.returnType() != QMetaType::QJsonObject){continue;}QJsonObject _tempObj;_meth.invoke(_obj,Qt::AutoConnection,Q_RETURN_ARG(QJsonObject,_tempObj));QString _key = _meth.name();_key = _key.remove("read_");_jsonObj[_key] = _tempObj;}return _jsonObj;
}inline void objLoad(const QJsonObject& jsonObj,QObject* _obj)
{auto _meatObj = _obj->metaObject();for(int i = _meatObj->propertyOffset(); i < _meatObj->propertyCount(); i++){auto _property = _meatObj->property(i);QJsonValue _val = jsonObj[_property.name()];_property.write(_obj,_val.toVariant());}for(int i = _meatObj->methodOffset(); i < _meatObj->methodCount(); i++){auto _meth = _meatObj->method(i);if(_meth.returnType() != QMetaType::Void){continue;}QString _key = _meth.name();_key = _key.remove("set_");QJsonObject tempObj = jsonObj[_key].toObject();_meth.invoke(_obj,Q_ARG(QJsonObject,tempObj));}
}

使用方式

  • 定义数据结构对象
#include "JsonHelper.h"class testStruct : public QObject
{Q_OBJECTQ_PROPERTY(int a READ READ_FUNC_NAME(a) WRITE WRITE_FUNC_NAME(a) CONSTANT)
public:testStruct &operator=(const testStruct& other){if(this != &other){this->a = other.a;}return *this;}int a;protected:READ_WRITE_VALUE(int,a)
};class myStruct : public QObject
{Q_OBJECTQ_PROPERTY(int id READ READ_FUNC_NAME(id) WRITE WRITE_FUNC_NAME(id) CONSTANT)Q_PROPERTY(QString name READ READ_FUNC_NAME(name) WRITE WRITE_FUNC_NAME(name) CONSTANT)Q_PROPERTY(QStringList nameList READ READ_FUNC_NAME(nameList) WRITE WRITE_FUNC_NAME(nameList) CONSTANT)
public:int id;QString name;QStringList nameList;testStruct _s1;protected:READ_WRITE_VALUE(int,id)READ_WRITE_VALUE(QString,name)READ_WRITE_VALUE(QStringList,nameList)READ_OBJECT(_s1)WRITE_OBJECT(_s1)};
  • 类型转换与加载
void int main()
{testStruct _ss;_ss.a = 12;myStruct _t;_t.id = 1;_t.name = "小明";_t.nameList = QStringList({"zhangsan","lisi"});_t._s1 = _ss;auto _obj = objDump(&_t);qDebug() << _obj;myStruct _t1;objLoad(_obj,&_t1);qDebug() << _t1.id << _t1.name << _t1.nameList << _t1._s1.a;return 0;
}

题外话

可以发现定义数据结构时还是比较繁琐的,如果有更方便的方式来定义数据结构,在实际场景中可用性将会变的更好。
因此,我实现了一个简单的代码自动生成工具,可以将struct结构体转换为满足上述条件的数据对象。如下所示。
在这里插入图片描述
这样就可以不用费劲的编写数据对象结构了。
工具和代码都已经上传GitHub了,感兴趣可以下载使用
GitHub链接
也提供了打包好的生成工具,可直接下载使用:
生成工具链接

相关文章:

简单实现QT对象的[json]序列化与反序列化

简单实现QT对象的[json]序列化与反序列化 简介应用场景qt元对象系统思路实现使用方式题外话 简介 众所周知json作为一种轻量级的数据交换格式&#xff0c;在开发中被广泛应用。因此如何方便的将对象数据转为json格式和从json格式中加载数据到对象中就变得尤为重要。 在python类…...

Unity肢体控制(关节控制)

前面的基础搭建网上自己搜&#xff0c;我这个任务模型网上也有&#xff0c;可以去官网看看更多模型&#xff0c;这里只讲述有模型如何驱动肢体的操作方式 第一步&#xff1a;创建脚本 第二步&#xff1a;创建Rig Builder 建空容器 加部件&#xff08;Rig&#xff09;,加了之后…...

Node.js | Yarn下载安装与环境配置

一、安装Node.js Yarn 是 Node.js 下的包管理工具&#xff0c;因此想要使用 Yarn 就必须先下载 Node.js。 推荐参考&#xff1a;Node.js | npm下载安装及环境配置教程 二、Yarn安装 打开cmd&#xff0c;输入以下命令&#xff1a; npm install -g yarn检查是否安装成功&…...

WPF如何全局应用黑白主题效果

灰白色很多时候用于纪念&#xff0c;哀悼等。那么使用 WPF如何来做到这种效果呢&#xff1f;要实现的这种效果&#xff0c;我们会发现&#xff0c;它其实不仅仅是要针对图片&#xff0c;而是要针对整个窗口来实现灰白色。 如果只是针对图片的话&#xff0c;我可以可以对图片进…...

[Qt] Qt删除文本文件中的某一行

需求 我们经常读一个文件或者直接往一个空白文件中写文本&#xff0c;那么该如何使用Qt在一个文本文件中删除某一行 代码 #include <QCoreApplication> #include <QIODevice> #include <QFile> #include <QTextStream> #include <QString> #i…...

【HarmonyOS学习日志(9)】一次开发,多端部署之界面级一多开发

关于一次开发&#xff0c;多端部署 一次开发多端部署就是指一套代码工程&#xff0c;一次开发上架&#xff0c;多端按需部署&#xff08;一多&#xff09;&#xff0c;用于支撑开发者快速高效地开发多终端设备上的应用&#xff0c;以节省开发成本。 HarmonyOS系统面向多终端&…...

基于Java+SSM+JSP+MYSQL实现的宠物领养收养管理系统功能设计与实现六

一、前言介绍&#xff1a; 免费学习&#xff1a;猿来入此 1.1 项目摘要 随着人们生活水平的提高&#xff0c;宠物已经成为越来越多家庭的重要成员。然而&#xff0c;宠物的数量增长也带来了一系列问题&#xff0c;如流浪宠物数量的增加、宠物健康管理的缺失以及宠物领养收养…...

Java项目实战II基于微信小程序的课堂助手(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 在数字化教…...

解析 Android WebChromeClient:提升 WebView 用户体验的关键组件

文章目录 一、总览二、详细说明三、一些实际和有趣的应用四、最佳实践五、与其他组件的比较六、安全性考虑&#xff1a;防止 XSS 攻击与数据泄露6.1 介绍6.2 代码案例6.2.1 输入过滤6.2.2 Content Security Policy (CSP) 案例 六、总结 在 Android 开发中&#xff0c;WebChrome…...

【LeetCode热题100】字符串

本篇博客记录了关于字符串相关的几道题目&#xff0c;包括最长公共前缀、最长回文子串、二进制求和、字符串相乘。 //解法1 class Solution { public:string longestCommonPrefix(vector<string>& strs) {string ret strs[0];for(int i 1 ; i < strs.size() ; i…...

OceanBase 闪回查询

前言 在OB中&#xff0c;drop表可以通过 回收站 或者 以往的备份恢复来还原单表。当delete数据时&#xff0c;由于delete操作的对象不会进入回收站&#xff0c;此时需要通过闪回查询功能查看delete的数据&#xff0c;以便后续恢复 本次实验版本为 OceanBase 4.2.1.8&#xff0…...

C++析构函数详解

C析构函数详解&#xff1a;对象销毁与资源清理 在 C 中&#xff0c;析构函数是与构造函数相对应的特殊成员函数&#xff0c;它在对象生命周期结束时被自动调用&#xff0c;用于执行对象销毁之前的清理操作。析构函数主要用于释放对象占用的资源&#xff0c;如动态分配的内存、打…...

【网络安全 | 漏洞挖掘】未授权获取AI聊天内容

未经许可,不得转载。 文章目录 两天前,我收到了一项私人项目的邀请,内容看起来像是一个聊天机器人,类似于 Gemini 或 ChatGPT。于是我开始测试该项目的一些业务逻辑漏洞和 IDOR(不当访问控制)漏洞。尽管这个产品拥有一个强大的安全团队,网站上也部署了 WAF(Web 应用防火…...

时间序列分析——移动平均法、指数平滑法、逐步回归法、趋势外推法等(基于Python实现)

第 11章——时间序列分析和预测 【例11-1】 绘制时间序列折线图—观察成分 【代码框11-1】——绘制时间序列折线图 # 图11-2的绘制代码 import pandas as pd import matplotlib.pyplot as plt plt.rcParams[font.sans-serif]=[SimHei...

opencv(c++)----图像的读取以及显示

opencv(c)----图像的读取以及显示 imread: 作用&#xff1a;读取图像文件并将其加载到 Mat 对象中。参数&#xff1a; 第一个参数是文件路径&#xff0c;可以是相对路径或绝对路径。第二个参数是读取标志&#xff0c;比如 IMREAD_COLOR 表示以彩色模式读取图像。 返回值&#x…...

PyTorch——从入门到精通:PyTorch基础知识(张量)【PyTorch系统学习】

什么是张量&#xff08;Tensor&#xff09; ​ 张量在数学中是一个代数对象&#xff0c;描述了与矢量空间相关的代数对象集之间的多重线性映射。张量是向量和矩阵概念的推广&#xff0c;可以理解为多维数组。作为数学中的一个基本概念&#xff0c;张量有着多种类型&#xff0c;…...

(笔记)ubuntu20安装jdk7,多版本管理

前往 Oracle JDK 7 下载页面&#xff08;需要 Oracle 账户&#xff09;&#xff0c;下载 JDK 7 的压缩包文件&#xff08;.tar.gz&#xff09;。 下载完成后&#xff0c;将文件解压到 /opt 目录&#xff1a; sudo tar -xzf jdk-7u<version>-linux-x64.tar.gz -C /opt 重…...

Python系列教程

文章目录 1. Python基础2. Python基础库3. Python数据分析 1. Python基础 语句数据类型表达式输入、输出与文件读写函数模块与包类与面向对象作用域与命名空间常用技巧与操作 2. Python基础库 Typing库 3. Python数据分析...

如何恢復電腦IP地址的手動設置?

手動設置IP地址後&#xff0c;可能會遇到一些網路連接問題&#xff0c;或者需要恢復到之前的自動獲取狀態。這篇文章將詳細介紹如何恢復電腦的IP地址設置。 為什麼需要恢復IP地址設置&#xff1f; 網路連接問題&#xff1a;手動設置IP地址後&#xff0c;可能會導致與路由器或…...

Linux 下敏感文件路径总结

Linux 下敏感文件路径总结 在服务器运维和安全测试过程中&#xff0c;掌握各类服务的关键配置文件路径、日志文件位置以及重要目录的存放位置至关重要。本文整理了 Linux 系统下常见服务&#xff08;如 Apache、Nginx、MySQL 等&#xff09;的路径结构&#xff0c;以及一些敏感…...

实战指南:如何用Hydra在Kali Linux上快速破解Telnet弱密码(附字典优化技巧)

Kali Linux渗透测试实战&#xff1a;Hydra高效破解Telnet服务的进阶技巧 在渗透测试和网络安全评估中&#xff0c;弱密码检测是基础但至关重要的环节。Telnet作为传统的远程管理协议&#xff0c;由于采用明文传输&#xff0c;成为安全测试的重点对象。本文将深入探讨如何利用Ka…...

Python实战:5分钟搞定Paillier同态加密的安装与基础使用(附避坑指南)

Python实战&#xff1a;5分钟搞定Paillier同态加密的安装与基础使用&#xff08;附避坑指南&#xff09; 隐私计算领域近年来发展迅猛&#xff0c;而同态加密作为其核心技术之一&#xff0c;正在金融、医疗等行业的数据协作场景中发挥越来越重要的作用。Paillier算法作为支持加…...

Lingbot-Depth-Pretrain-VitL-14处理复杂光照与反射场景效果展示

Lingbot-Depth-Pretrain-VitL-14处理复杂光照与反射场景效果展示 深度估计技术&#xff0c;简单来说就是让计算机像人眼一样&#xff0c;判断出画面中每个物体离我们有多远。这项技术在自动驾驶、机器人导航、增强现实等领域都扮演着关键角色。然而&#xff0c;当场景中出现一…...

nlp_gte_sentence-embedding_chinese-large在软件测试用例生成中的应用

nlp_gte_sentence-embedding_chinese-large在软件测试用例生成中的应用 1. 引言 软件测试是确保产品质量的关键环节&#xff0c;但传统的手工编写测试用例方式往往效率低下且容易遗漏重要场景。测试工程师需要反复阅读需求文档&#xff0c;手动提取测试要点&#xff0c;这个过…...

Kimi-VL-A3B-Thinking Chainlit定制化开发:添加历史记录/多用户会话/图片标注功能

Kimi-VL-A3B-Thinking Chainlit定制化开发&#xff1a;添加历史记录/多用户会话/图片标注功能 1. 项目背景与模型介绍 Kimi-VL-A3B-Thinking是一款基于混合专家架构(MoE)的开源视觉语言模型(VLM)&#xff0c;在多模态推理和长上下文理解方面表现出色。该模型仅激活2.8B参数就…...

OpenClaw进阶:利用GLM-4.7-Flash实现复杂任务链式执行

OpenClaw进阶&#xff1a;利用GLM-4.7-Flash实现复杂任务链式执行 1. 为什么需要链式任务执行 上周我在整理项目文档时&#xff0c;遇到了一个典型的多步骤任务&#xff1a;需要从十几个Markdown文件中提取关键数据&#xff0c;整理成Excel表格&#xff0c;然后根据内容生成分…...

单片机开发三大软件架构对比与实践

单片机开发常用软件架构深度解析1. 项目概述在嵌入式系统开发中&#xff0c;软件架构设计直接影响系统的可靠性、可维护性和实时性。本文系统分析三种主流单片机软件架构方案&#xff0c;包括时间片轮询法、操作系统方案和前后台顺序执行法&#xff0c;为开发者提供架构选型参考…...

智能工单管理系统 2026 怎么挑?五款热门平台对比,适配企业各类业务场景

工单智能化应用&#xff1a;帮您告别工单苦海 传统工单系统的痛点&#xff0c;本质是信息处理效率与用户体验的矛盾。随着AI 的发展&#xff0c;工单智能化应用的核心逻辑转变为&#xff0c;通过AI技术将“人找信息”转变为“信息找人”&#xff0c;甚至“预测需求”。 工单管…...

Java 四种安全加载 P12 证书的方案

文章目录从文件绝对路径加载【最常用、最稳定】从 resources 目录加载从 byte [] 字节数组加载从 Base64 字符串加载如果文章对您有用&#xff0c;请关注点赞加收藏&#xff0c;博主会持续更新相关的专栏笔记&#x1fae1; 从文件绝对路径加载【最常用、最稳定】 适合&#xf…...

League-Toolkit:革新英雄联盟体验的效率倍增工具集

League-Toolkit&#xff1a;革新英雄联盟体验的效率倍增工具集 【免费下载链接】League-Toolkit 兴趣使然的、简单易用的英雄联盟工具集。支持战绩查询、自动秒选等功能。基于 LCU API。 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit League-Toolkit是一…...