本文以jsoncpp库为基础,设计这样一个可以支持一个函数 可以一行代码 unmarshal /marshal 对象,需要的朋友小伙伴可以参考以下
背景:
在项目里经常遇到对象和json
字符串的相互转换这类问题,在大多数程序里,一般这个问题都比较有比较好的解决方法,往往一个函数搞定。但是到了c++
这边却需要我们手撸json库一个一个字段初始化/序列化。如果这时候有一个函数 可以一行代码 unmarshal /marshal
对象岂不是很方便?本文以jsoncpp
库为基础,设计这样一个可以支持这种功能的函数,下面进入正题~
1、设计思路
以unmarshal
为例,我们最终的函数是打造两个这样的模板函数 :
一个从string
的josn
直接反序列化对象,一个从jsoncpp
库的json
对象,反序列化对象。
由于json
是具有自递归结构的,所以在设计时,应该也是以递归的方式解决复杂的组合类,我们可以简单的把程序中的变量分为下面几类:
这样我们只需要把这几个场景的 Unmarshal
实现了,整体的Unmarshal
也就实现了。模板设计的类图应该和我们的分类相对应:
在实现中要注意以下几点:
- 每个分类的
Unmarshal
模板具有排他性,也就是说基本类型在编译期间只能匹配解析基本类型的模板 - 由于1的保证和这些模板函数名称都是
Unmarshal
,所以他们之间可以相互嵌套调用对方。 - 指针、和原生数组会涉及到空间分配和长度检测会使得情况变得复杂,本次设计支持的范围不包含对指针、原生数组的支持。
2、匹配基本类型的Unmarshal模板
3、匹配stl容器/其他第三方类库的Unmarshal模板
4、匹配自定义struct/class的Unmarshal模板
实现一组只能匹配自己定义的struct/class
就需要我们定义的对象有一些特殊的标志,才能被模板函数识别。在这里选择给我们自己定义的类都实现public的unmarshal
方法(实现方式后面讲),这样当编译时发现一个对象含有 public
的 unmarshal
方法时,就知道使是我们自己定义的类,然后就调用特定的模板函数,这里用到到了一个C++的语法 SFINAE(Substitution Failure Is Not An Error) 和std库中enable_if
我们先来看一下C++ std库中 enable_if 的简要实现:
SFINAE 准则就是匹配失败并不是错误,如果编译器在匹配一个模板时引发了错误,这时候编译器应当尝试下一个匹配,而不应该报错中止。利用这条规则和enable_if,解析我们自己struct/class Umarshal
模板设计如下:
好了,至此我们对三种基本类型的Umarshal
函数设计好了,这时候任意一个T类型 在调用Unmarshal
时,最终会与上面三种其中一个匹配。json 为string的可以利用上面的Unmarshal
再封装一个版本:
接下来我们看如何在自定义的类中实现unmarshal
函数:
显然如果field数量很多,就很麻烦,而且解析每个field
时,代码格式非常相似,是否存在一个宏可以自动生成呢?答案是肯定的。talk is cheap
,show me the code
,上代码!
5、测试
我们的Umarshal
和 Marshal
函数编写好了,现在测试一下吧:
场景:有一个map
对象存着教师的信息,每个教师又保存着ta教学生信息,数据结构定义如下:
测试代码:
到此这篇关于C++ 轻量级对象JSON序列化实现详情的文章就介绍到这了,更多相关C++ 轻量级对象JSON序列化实现内容请搜索编程学习网以前的文章希望大家以后多多支持编程学习网!