
🔥小叶-duck:个人主页
❄️个人专栏:《Data-Structure-Learning》《C++入门到进阶&自我学习过程记录》
《Linux系统从入门到实践》《Linux网络从入门到实践》
✨未择之路,不须回头
已择之路,纵是荆棘遍野,亦作花海遨游
目录
[一、Json 简介](#一、Json 简介)
[1.1 基本结构](#1.1 基本结构)
[1.2 语法规则](#1.2 语法规则)
[1.3 演示示例](#1.3 演示示例)
[1.4 用途](#1.4 用途)
[二、JsonCpp 介绍](#二、JsonCpp 介绍)
[2.1 JsonCpp 安装](#2.1 JsonCpp 安装)
[三、JsonCpp 使用](#三、JsonCpp 使用)
[3.1 包含头文件](#3.1 包含头文件)
[3.2 链接库](#3.2 链接库)
[3.3 Json::Value 类型枚举](#3.3 Json::Value 类型枚举)
[3.4 中间数据转储类 Json::Value 常用 API](#3.4 中间数据转储类 Json::Value 常用 API)
[3.4.1 代码案例:Json::Value 构造 JSON](#3.4.1 代码案例:Json::Value 构造 JSON)
[3.5 序列化](#3.5 序列化)
[3.5.1 核心类介绍](#3.5.1 核心类介绍)
[3.5.2 序列化代码示例](#3.5.2 序列化代码示例)
[3.6 反序列化](#3.6 反序列化)
[3.6.1 核心类介绍](#3.6.1 核心类介绍)
[3.6.2 反序列化代码示例](#3.6.2 反序列化代码示例)
[3.6.3 序列化 & 反序列化对比小结](#3.6.3 序列化 & 反序列化对比小结)
[四、Jsoncpp 二次封装](#四、Jsoncpp 二次封装)
[4.1 封装目的](#4.1 封装目的)
[4.2 接口设计思路](#4.2 接口设计思路)
[4.3 头文件 Myjson.h](#4.3 头文件 Myjson.h)
[4.4 源文件 Myjson.cc 实现](#4.4 源文件 Myjson.cc 实现)
[4.5 测试代码 Myjson_test.cc](#4.5 测试代码 Myjson_test.cc)
[4.6 Makefile](#4.6 Makefile)
[4.7 编译与运行](#4.7 编译与运行)
[4.8 封装优势小结](#4.8 封装优势小结)
前言
在 C++ 后端网络项目开发中,配置文件读取、前后端报文交互、日志结构化输出,都离不开 JSON 这种轻量文本格式。原生 C++ 语言本身并没有内置 JSON 解析能力,我们需要借助第三方库完成 JSON 的构造、序列化与反序列化工作,JsonCpp 便是 C++ 生态里经典、易用的老牌 JSON 开源库。
本篇文章将从 JSON 基础语法入手,先介绍 JsonCpp 的安装方式、核心数据结构
Json::Value以及常用 API,手把手演示 JSON 对象构建、序列化输出、字符串反解析等基础操作。 在掌握原生 JsonCpp 使用之后,我们会发现原生接口在工程使用上存在一定冗余,错误处理不够统一。因此我们会基于 JsonCpp 做一层二次封装,自研MyJson工具层,对外提供简洁的序列化、反序列化接口,统一异常与日志处理,屏蔽底层 JsonCpp 的复杂细节。
一、Json 简介
JSON (JavaScript Object Notation)是一种轻量级的数据交换格式 ,易于人工阅读编写,同时便于机器解析与生成。它源自 JavaScript 的子集,但JSON 本身语言无关,几乎所有编程语言都提供了对应的解析工具。
1.1 基本结构
JSON 只有两种核心容器结构,所有复杂数据都由二者组合嵌套而成:
- 对象: 一组无序键值对集合,使用**大括号 {}**包裹;
- 数组: 一组有序值的集合,使用**方括号 \[\]**包裹;
- **值的类型:**支持字符串、数字、布尔值 true/false、null,也可以嵌套对象、数组。
1.2 语法规则
JSON 有严格的语法规范,书写时必须遵守,否则解析会直接失败:
- 键值对 格式为 "key": value ,键与值之间用 **冒号 :**分隔;
- 同一层级多个键值对 / 数组元素之间,使用 **逗号
,**分隔; - 所有键必须为字符串类型,且必须使用双引号
"包裹,单引号不符合 JSON 标准。
1.3 演示示例
bash
{
"name": "John Doe",
"age": 30,
"is_student": false,
"skills": ["JavaScript", "Python", "C++"],
"address": {
"street": "123 Main St",
"city": "Anytown",
"state": "CA"
}
}
1.4 用途
- **数据存储:**作为一种数据格式,用于文件和数据库存储。
- **数据交换:**作为 APIs 和网络请求中数据交换的标准格式。
- **配置文件:**用于应用程序的配置信息。
二、JsonCpp 介绍
JsonCpp 是一个高性能的C++ JSON 库 ,专门用来处理 JSON 数据 。
它完整支持 JSON 标准,具备解析 JSON 字符串、生成 JSON 字符串、读写 JSON 对象与数组等能力。

2.1 JsonCpp 安装
Ubuntu 直接命令安装:
bash
sudo apt install libjsoncpp-dev
CentOS 直接命令安装:
CentOS 系统可以通过 yum 包管理器直接安装开发库:
bash
# CentOS7 / CentOS8
sudo yum install jsoncpp-devel
说明: CentOS 的包名后缀是
-devel,和 Ubuntu 的-dev命名习惯不一样。
验证是否安装成功:
安装完成后,可通过下面命令查看头文件与库文件,验证是否安装成功:
bash
# 查看头文件
ls /usr/include/jsoncpp/
# 查看库文件
ls /usr/lib/x86_64-linux-gnu/libjsoncpp*
安装完成结果:
三、JsonCpp 使用
3.1 包含头文件
使用该类需要引入头文件:
cpp
#include <jsoncpp/json/json.h>
3.2 链接库
编译时,需要链接 jsoncpp 库,编译选项添加:
bash
-ljsoncpp
3.3 Json::Value 类型枚举
Json::ValueType 枚举定义了 JSON 支持的全部数据类型:
cpp
namespace Json {
enum ValueType {
nullValue = 0, ///< 'null' 值
intValue, ///< 有符号整型
uintValue, ///< 无符号整型
realValue, ///< 浮点double值
stringValue, ///< UTF-8字符串
booleanValue, ///< 布尔值
arrayValue, ///< 数组(有序列表)
objectValue ///< 对象,键值对集合
};
3.4 中间数据转储类 Json::Value 常用 API
JsonCpp 中最核心的类是 Json::Value,作为内存中间数据转储类。
- 序列化场景: 将 C++ 中的各类数据,先存入
Json::Value对象,再转为 JSON 字符串。 - 反序列化场景: 解析 JSON 字符串,解析后的结果全部存放到
Json::Value对象,之后从中读取字段。
cpp
class JSON_API Value {
public:
// 拷贝交换
void swap(Value& other);
void copy(const Value& other);
// 类型转换接口:从Value取出对应类型数据
const char* asCString() const;
String asString() const;
Int asInt() const;
UInt asUInt() const;
Int64 asInt64() const;
UInt64 asUInt64() const;
float asFloat() const;
double asDouble() const;
bool asBool() const;
// 类型判断接口,判断当前Value是什么类型
bool isNull() const;
bool isBool() const;
bool isInt() const;
bool isInt64() const;
bool isUInt() const;
bool isUInt64() const;
bool isIntegral() const;
bool isDouble() const;
bool isNumeric() const;
bool isString() const;
bool isArray() const;
bool isObject() const;
// 数组相关API
ArrayIndex size() const;
bool empty() const;
void clear();
void resize(ArrayIndex newSize);
Value& operator[](ArrayIndex index); // 通过下标访问数组元素
Value& append(const Value& value); // 向数组追加元素
// 对象键值访问API
Value& operator[](const char* key);
Value& operator[](const String& key);
void removeMember(const String& key); // 删除指定key
bool isMember(const String& key) const; // 判断key是否存在
// 序列化:将Value对象转为格式化JSON字符串
String toStyledString() const;
};
核心接口说明:
- **\[\] 运算符:**用于对象读写键值对。val"name" = "zhangsan",直接给对象的 key 赋值。
- **append():**数组专用接口,往数组里面追加元素。
- **asXXX()系列:**取值接口。把Json::Value里的数据转成 C++ 基础类型,例如 .asString()、.asDouble()。
- **isXXX()系列:**类型判断。判断当前节点是 null / 对象 / 数组 / 数字等,防止取值类型不匹配。
- **toStyledString():**序列化函数。把内存中的Json::Value转为带缩进格式化的 JSON 字符串。

3.4.1 代码案例:Json::Value 构造 JSON
cpp
#include <iostream>
#include <jsoncpp/json/json.h>
int main()
{
// 1. 创建Json::Value对象,默认是object类型,用来存储键值对
Json::Value val;
val["name"] = "zhangsan"; // []运算符,给对象添加key-value,字符串
val["age"] = 18; // 写入整型
// 给score数组追加浮点元素,val["score"]自动识别为数组
val["score"].append(76.5);
val["score"].append(86.5);
val["score"].append(96.5);
// 2. 手动创建一个数组对象
Json::Value arr(Json::arrayValue);
// 创建对象item1,存入id和name,追加到数组arr中
Json::Value item1;
item1["id"] = 1;
item1["name"] = "Tom";
arr.append(item1);
// 创建对象item2,存入id和name,追加到数组arr中
Json::Value item2;
item2["id"] = 2;
item2["name"] = "Jerry";
arr.append(item2);
// 将数组arr作为users字段,存入顶层val对象
val["users"] = arr;
// 3. 序列化:Value对象转格式化JSON字符串
std::string json_str = val.toStyledString();
// 打印输出json字符串
std::cout << json_str << std::endl;
return 0;
}
编译命令参考:
bash
g++ json_test1.cc -o json_test1 -ljsoncpp
运行输出 JSON:

3.5 序列化
序列化的目标: 将内存中 Json::Value 对象,转换为 JSON 格式字符串。
JsonCpp 提供 StreamWriter 作为序列化核心类,采用建造者模式来创建写入器对象,支持自定义序列化格式。
3.5.1 核心类介绍
cpp
namespace Json {
class JSON_API StreamWriter {
public:
// 核心写接口:把root的json数据输出到输出流sout
virtual int write(Value const& root, OStream* sout);
// 建造者工厂基类
class JSON_API Factory {
public:
virtual StreamWriter* newStreamWriter();
};
};
// 全局辅助函数,根据工厂配置生成json字符串
String JSON_API writeString(
StreamWriter::Factory const& factory,
Value const& root);
// StreamWriter建造者实现类,用来配置序列化参数
class streamWriterBuilder : public StreamWriter::Factory {
public:
Json::Value settings_;
};
}
- StreamWriter:序列化核心类。write方法完成写入,接收Json::Value对象与输出流,返回值代表执行状态,一般情况下序列化不会失败。
- StreamWriter::Factory:工厂基类。定义创建StreamWriter的接口。
- StreamWriterBuilder:建造者派生类。继承工厂,用于配置序列化参数(缩进、换行等),调用 newStreamWriter() 创建 StreamWriter 实例。
设计思路: 建造者模式,把对象构造 和对象使用分开。我们先通过 Builder 配置输出风格,再生产对应的 StreamWriter,实现灵活自定义 JSON 输出格式。

3.5.2 序列化代码示例
cpp
#include <iostream>
#include <jsoncpp/json/json.h>
#include <memory>
#include <sstream>
int main()
{
// 1. 创建Json::Value对象,默认是object类型,用来存储键值对
Json::Value val;
val["name"] = "zhangsan"; // []运算符,给对象添加key-value,字符串
val["age"] = 18; // 写入整型
// 给score数组追加浮点元素,val["score"]自动识别为数组
val["score"].append(76.5);
val["score"].append(86.5);
val["score"].append(96.5);
// 2. 创建建造者对象,用于配置序列化输出参数
Json::StreamWriterBuilder builder;
builder["indentation"] = ""; // 配置缩进为空字符串,输出紧凑无换行的json
// 3. 通过建造者newStreamWriter()生成StreamWriter序列化对象
// 使用unique_ptr自动管理内存,避免内存泄漏
std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
// 4. 字符串流,用来接收序列化之后的json字符串
std::stringstream ss;
// 调用write接口,将val写入字符串流ss
int res = writer->write(val, &ss);
if (res != 0)
{
std::cout << "write false" << std::endl;
return -1;
}
// 5. 从stringstream中取出完整json字符串
std::string json_str = ss.str();
std::cout << json_str << std::endl;
return 0;
}
代码分析:
- **数据组装部分:**构建Json::Value对象,写入普通键值对与数组,和前面代码基础用法一致。
- StreamWriterBuilder builder: 实例化建造者,builder"indentation" = "" 修改缩进配置。
如果设置" ",输出就是带缩进格式化 JSON;空字符串代表紧凑模式,去掉多余换行空格。 - **builder.newStreamWriter():**工厂方法,动态创建StreamWriter实例,交给 unique_ptr 托管,自动释放内存。
- **writer->write(val, &ss):**序列化核心调用,将 Json::Value 里面的所有数据,写入 C++ 字符串流 stringstream。返回 0 代表成功,非 0 表示异常。
- **ss.str():**从流中提取最终的 JSON 字符串,后续可以打印、写入文件或者网络发送。
编译命令:
bash
g++ json_test2.cc -o json_test2 -ljsoncpp
运行结果展示:

3.6 反序列化
反序列化作用:把 JSON 格式的字符串,解析到内存的 Json::Value 对象中,之后我们就可以读取里面存储的数据。
和序列化一样,JsonCpp 这里同样使用建造者模式,通过 CharReader 完成解析,CharReaderBuilder用来生产 CharReader 实例。
3.6.1 核心类介绍
cpp
namespace Json {
class JSON_API CharReader {
public:
// 核心解析接口,将一段json文本解析存入root
virtual bool parse(
char const* beginDoc, // json字符串起始地址
char const* endDoc, // json字符串末尾地址
Value* root, // 输出:解析结果存入这个Value对象
String* errs) = 0; // 输出:解析失败时,存放错误信息,默认为nullptr
// 工厂基类,定义创建CharReader的接口
class JSON_API Factory {
virtual CharReader* newCharReader() const = 0;
};
};
// CharReader建造者,继承工厂,可配置解析参数
class JSON_API CharReaderBuilder : public CharReader::Factory {
public:
Json::Value settings_;
CharReader* newCharReader() const override;
};
}
- **CharReader:反序列化核心类。**parse是解析函数。传入字符串首尾指针,解析成功返回 true;失败返回 false,错误信息存入 errs。
- CharReader::Factory:工厂抽象基类。规定创建 CharReader 的接口。
- CharReaderBuilder:建造者实现类,继承 Factory。调用newCharReader()生成 CharReader 对象,也可以通过 settings_配置解析规则。
**整体流程:实例化建造者 -> 通过建造者生成 CharReader 对象 -> 调用 parse 完成反序列化。**和前面 StreamWriter 序列化的设计完全对应。
3.6.2 反序列化代码示例
cpp
#include <iostream>
#include <jsoncpp/json/json.h>
#include <memory>
#include <sstream>
int main()
{
// 错误写法;在字符串中不能直接写双引号,否则会识别出现问题(编译器会识别"{"是字符串,后续代码是乱的)
// std::string json_str = "{"age":18,"name":"zhangsan","score":[76.5,86.5,96.5]}";
// 如果需要在字符串中使用双引号,就需要大量转义\",很麻烦
// std::string json_str = "{\"age\":18,\"name\":\"zhangsan\",\"score\":[76.5,86.5,96.5]}";
// C++11原始字符串字面量R"()",不需要手动转义双引号,简化json字符串书写
std::string json_str = R"({"age":18,"name":"zhangsan","score":[76.5,86.5,96.5]})";
// 1.实例化建造者对象
Json::CharReaderBuilder builder;
// 2.调用newCharReader生产CharReader,unique_ptr自动管理内存
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
// 3.定义Value对象,用于存放解析之后的数据
Json::Value val;
std::string err_str; // 保存解析失败的错误信息
// 4.核心parse解析接口
// 参数1:字符串起始指针;参数2:字符串末尾指针;参数3:解析输出对象;参数4:错误信息
bool res = reader->parse(json_str.c_str(), json_str.c_str() + json_str.size(), &val, &err_str);
if (res == false)
{
std::cout << "parse json failed, err: " << err_str << std::endl;
return -1;
}
// 5.解析成功,从Json::Value读取数据
std::cout << "name: " << val["name"].asString() << std::endl;
std::cout << "age: " << val["age"].asInt() << std::endl;
// 读取数组,先判断节点类型,防止数组不存在或者不是数组,避免程序崩溃
int size = val["score"].size();
if (!(val["score"].isNull()) && val["score"].isArray())
{
for (int i = 0; i < size; i++)
{
std::cout << "score: " << val["score"][i].asDouble() << std::endl;
}
}
return 0;
}
代码分析:
- JSON 字符串定义 使用 C++ 原始字符串
R"(...)",字符串内部的双引号不用转义。如果不用 R,JSON 里每个"都要写成\",代码可读性很差,也容易写错。 - parse 解析函数:
- **json_str.c_str():**字符串起始地址
- **json_str.c_str() + json_str.size():**字符串末尾地址(左闭右开区间)
- **&val:**解析完成后,json 数据存入这个 Json::Value 对象
- **&err_str:**解析出错,会把错误描述字符串写入 err_str 返回 bool:true 代表解析成功,false 解析失败。
- 读取基础字段 val"name".asString():取出 name 节点,转为 std::string;asInt() 取出 age 整型。必须调用 asXX (),不能直接输出 val "name"。
- 数组安全读取先判断 val"score" 不为空,并且类型是数组,再遍历读取。工程开发中这个判断非常关键:如果 json 缺少 score 字段,直接遍历会触发异常崩溃。
编译命令:
bash
g++ json_test3.cc -o json_test3 -ljsoncpp
运行结果展示:

3.6.3 序列化 & 反序列化对比小结
- **序列化:**StreamWriterBuilder → StreamWriter → write(),内存 Value → JSON 字符串
- 反序列化: CharReaderBuilder → CharReader → parse(),JSON 字符串 → 内存 Value
两套接口都是建造者模式,API 设计对称。
四、Jsoncpp 二次封装
4.1 封装目的
原生 jsoncpp 库直接使用时,每次序列化 / 反序列化都需要重复编写建造器对象创建、unique_ptr 管理、错误判断等样板代码。 在项目中反复手写会造成大量重复代码,不利于统一的错误处理与日志打印。 因此我们封装一个 Json 工具类,对外暴露简洁接口,把底层 jsoncpp 的细节全部隐藏。
4.2 接口设计思路
- 工具类名称:MyJson::JSON ,所有接口定义为静态成员函数,不需要实例化对象,直接类名调用
- 序列化接口:
- **输入:**Json::Value&(内存中的 json 对象)
- **返回:**std::optional<std::string>,成功返回 json 字符串;失败返回std::nullopt
- 反序列化接口:
- **输入:**std::string&(json 格式字符串)
- 返回:std::optional<Json::Value>,成功返回解析后的 Value 对象;失败返回std::nullopt
std::optional 是 C++17 特性,适合表示可能失败的返回值,可以清晰区分「调用成功带回结果」和「调用失败无结果」,比输出参数、返回错误码更现代。

4.3 头文件 Myjson.h
cpp
#ifndef __MYJSON_H__
#define __MYJSON_H__
#include <iostream>
#include <jsoncpp/json/json.h>
#include <memory>
#include <sstream>
#include <optional>
#include "Mylog.h"
using namespace Mylog;
namespace MyJson
{
class JSON
{
public:
// 序列化:Json::Value对象 -> json字符串
static std::optional<std::string> serialize(Json::Value &val);
// 反序列化:json字符串 -> Json::Value对象
static std::optional<Json::Value> unserialize(std::string &input);
};
}
#endif
头文件代码分析:
- 引入 optional 头文件,用于接口返回值;同时引入日志模块Mylog.h,失败时打印日志
- 放在 MyJson 命名空间,避免和其他库命名冲突
- 两个静态函数,对外屏蔽 StreamWriter、CharReaderBuilder 这些底层建造者细节
4.4 源文件 Myjson.cc 实现
cpp
#include "Myjson.h"
namespace MyJson
{
std::optional<std::string> JSON::serialize(Json::Value &val)
{
// 1. 创建序列化建造者,生产StreamWriter
Json::StreamWriterBuilder builder;
std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
std::stringstream ss;
// 2. 将Value对象写入字符串流
int ret = writer->write(val, &ss);
if (ret != 0)
{
// 序列化失败,使用自定义日志打印错误
ERR("序列化失败!");
return std::nullopt;
}
// 序列化成功,返回字符串
return ss.str();
}
std::optional<Json::Value> JSON::unserialize(std::string &input)
{
// 1. 创建反序列化建造者,生产CharReader
Json::CharReaderBuilder builder;
std::unique_ptr<Json::CharReader> reader(builder.newCharReader());
Json::Value val;
std::string err_str;
// 2. 调用parse进行解析
bool ret = reader->parse(input.c_str(), input.c_str() + input.size(), &val, &err_str);
if (ret == false)
{
// 反序列化失败,打印原始输入字符串与错误信息
ERR("反序列化失败: {}, {}", input, err_str);
return std::nullopt;
}
// 解析成功,返回Value对象
return val;
}
}
源码逐段分析:
serialize 序列化函数
StreamWriterBuilder:建造者,用来创建StreamWriter对象,unique_ptr自动管理内存,不用手动 deletestd::stringstream ss:内存流,接收序列化后的文本writer->write(val, &ss):将 Json::Value 中的数据转为 json 文本写入流,返回 0 代表成功- 失败:打印日志,返回
std::nullopt;成功取出 stringstream 里的字符串返回
unserialize 反序列化函数
CharReaderBuilder:反序列化建造者,创建 CharReader 解析器reader->parse():核心解析函数,传入字符串首尾指针,解析结果存入 val,错误信息存入 err_str- 解析失败:日志打印原始字符串和错误原因,返回
std::nullopt;成功返回解析好的Json::Value
4.5 测试代码 Myjson_test.cc
cpp
#include "Myjson.h"
using namespace MyJson;
void Serialize_test()
{
Json::Value val;
val["name"] = "zhangsan";
val["age"] = 18;
val["score"].append(76.5);
val["score"].append(86.5);
val["score"].append(96.5);
// 错误写法:
// std::string json_str = serialize(val);
// std::cout << json_str << std::endl;
auto result = JSON::serialize(val);
std::string json_str = result.value();
std::cout << json_str << std::endl;
}
void UnSerialize_test()
{
std::string json_str = R"({"age":18,"name":"zhangsan","score":[76.5,86.5,96.5]})";
auto result = JSON::unserialize(json_str);
Json::Value val = result.value();
std::cout << "name: " << val["name"].asString() << std::endl;
std::cout << "age: " << val["age"].asInt() << std::endl;
int size = val["score"].size();
if (!(val["score"].isNull()) && val["score"].isArray())
{
for (int i = 0; i < size; i++)
{
std::cout << "score: " << val["score"][i].asDouble() << std::endl;
}
}
}
int main()
{
Serialize_test();
UnSerialize_test();
return 0;
}
测试代码说明:
- Serialize_test:构造 Json::Value 对象,调用封装好的 JSON::serialize 一键序列化,拿到 json 字符串
- UnSerialize_test:传入 json 字符串,调用 JSON::unserialize 一键反序列化,得到 Json::Value,读取内部字段
- 使用方式极大简化,不再需要每次手写建造者、parse、write 等底层代码,业务代码只关心数据本身
4.6 Makefile
bash
CFLAGS=-I../source
myjson_test:Myjson_test.cc ../source/Myjson.cc ../source/Mylog.cc
g++ -o $@ $^ -std=c++17 $(CFLAGS) -lpthread -ljsoncpp -lfmt -lspdlog
.PHONY:clean
clean:
rm -rf myjson_test
- **-std=c++17:**必须开启 C++17,std::optional是 C++17 引入的特性
- **-ljsoncpp:**链接 jsoncpp 库;同时链接日志相关 spdlog、fmt 库
- **-I../source:**指定头文件搜索路径,找到 Myjson.h、Mylog.h
4.7 编译与运行


4.8 封装优势小结
- **简化业务代码:**业务层一行调用,不用重复写建造器、内存管理、错误处理
- **统一错误处理:**所有 json 解析失败,统一走日志输出,方便项目问题排查
- **底层隔离:**后续更换 json 库(例如 nlohmann),只需要修改 Myjson.cc 内部实现,业务代码完全不用改动
- **内存安全:**内部使用 unique_ptr,自动释放解析器 / 写入器,避免内存泄漏
**注意点:**调用.value()获取 optional 里面的值,必须保证 optional 有值;工程中严谨写法要先判断 if(result.has_value()),再调用 value (),否则会抛异常。
结束语
到这里,本篇 JsonCpp 的实战内容就全部结束了。我们从 JSON 基础概念出发,学习了 JsonCpp 库的安装、核心 API 的调用,亲手完成 JSON 对象构造、序列化与反序列化等基础功能。
原生 JsonCpp 功能完备,但直接在业务代码中裸用会带来代码冗余、错误处理零散等问题。因此我们进行了二次封装,搭建
MyJson工具层,将底层库的复杂接口做收拢,对外暴露简洁易用的序列化、反序列化能力,统一错误返回与日志处理。同时也探讨了工具类接口的设计思路,理解为什么序列化函数适合设计为静态成员函数,体会第三方库封装的工程思想。本次封装的 MyJson 模块可以直接嵌入到 C++ 后端项目中,用于配置解析、网络报文处理。这个二次封装的思路也具备通用性,后续遇到其他第三方库时,都可以借鉴这套思路,屏蔽底层细节、统一异常处理,降低业务层的开发成本。
