Json简单的实现
目录
1.了解stringstream
✅ 1. 头文件
✅ 2. 基本用法速览
✅ 3. 完整示例
✅ 4. 与 JSON 结合
✅ 一句话总结
2.工厂类
✅ 1. 最简单静态工厂(无继承)
✅ 2. 工厂方法(多态扩展)
✅ 3. 抽象工厂(产品族)
✅ 4. 模板工厂(零成本运行时)
✅ 5. 注册式工厂(字符串到对象)
✅ 一句话总结
3.实现序列化
1. 函数功能
2. 关键代码解析
(1) 使用 Json::StreamWriterBuilder
(2) 创建 Json::StreamWriter
(3) 序列化 JSON 到字符串流
(4) 错误处理
(5) 获取结果字符串
4.parse (把一段 JSON 字符串转成内存中的 Json::Value对象)
✅ 1. 头文件
✅ 2. 最简解析(字符串 → Json::Value)
✅ 3. 常用取值
✅ 4. 从文件解析
⚠️ 5. 常见错误
✅ 一句话
5.实现反序列化
1. 函数功能
2. 关键代码解析
(1) 使用 Json::CharReaderBuilder
(2) 创建 Json::CharReader
(3) 解析 JSON 字符串
6.R
✅ 语法
✅ 对比示例
✅ 在你的 JSON 例子
✅ 一句话
7.测试与实现汇总
1.了解stringstream
std::stringstream
是 C++ 标准库里的 字符串流,功能 = “像文件一样读写字符串”,常用于 格式化、类型转换、分词、拼接。
✅ 1. 头文件
#include <sstream>
✅ 2. 基本用法速览
场景 | 示例 |
---|---|
int → string | std::string s = std::to_string(123); 或 stringstream ss; ss << 123; ss.str(); |
string → int | stringstream ss("123"); int x; ss >> x; |
拼接字符串 | stringstream ss; ss << "a=" << 3 << ",b=" << 4; std::cout << ss.str(); |
按空格/逗号分词 | stringstream ss("a b c"); std::string word; while (ss >> word) std::cout << word << '\n'; |
✅ 3. 完整示例
#include <sstream>
#include <iostream>int main() {// 1) 构造std::stringstream ss;// 2) 写入int a = 5, b = 7;ss << "a=" << a << ",b=" << b;// 3) 读取std::string str = ss.str(); // "a=5,b=7"std::cout << str << '\n';// 4) 重新使用ss.str(""); // 清空内容ss.clear(); // 清空状态位ss << 3.14;double pi;ss >> pi; // 3.14std::cout << pi << '\n';
}
✅ 4. 与 JSON 结合
std::stringstream ss;
Json::Value v;
ss << R"({"x":10,"y":20})";
Json::parseFromStream(Json::CharReaderBuilder(), ss, &v, nullptr);
✅ 一句话总结
stringstream
= “内存里的 I/O 流”,既能 格式化输出,也能 解析输入,是 C++ 里小工具级的瑞士军刀。
2.工厂类
工厂类(Factory)是一种 创建型设计模式,用来 统一、灵活地创建对象,而不让客户端直接依赖具体类。下面用 最简例子 + 完整演进 带你一次看懂。
✅ 1. 最简单静态工厂(无继承)
enum class ShapeType { CIRCLE, RECT };class ShapeFactory {
public:static std::unique_ptr<Shape> create(ShapeType t) {switch (t) {case ShapeType::CIRCLE: return std::make_unique<Circle>();case ShapeType::RECT: return std::make_unique<Rect>();default: return nullptr;}}
};// 客户端
auto shape = ShapeFactory::create(ShapeType::CIRCLE);
✅ 2. 工厂方法(多态扩展)
class ShapeFactory {
public:virtual std::unique_ptr<Shape> create() = 0;virtual ~ShapeFactory() = default;
};class CircleFactory : public ShapeFactory {
public:std::unique_ptr<Shape> create() override { return std::make_unique<Circle>(); }
};// 新增形状 -> 新增工厂,符合开闭原则
✅ 3. 抽象工厂(产品族)
class GUIFactory {
public:virtual std::unique_ptr<Button> createButton() = 0;virtual std::unique_ptr<TextEdit> createTextEdit() = 0;
};class WinFactory : public GUIFactory { /* Windows 实现 */ };
class MacFactory : public GUIFactory { /* macOS 实现 */ };
✅ 4. 模板工厂(零成本运行时)
template<typename T>
class GenericFactory {
public:static std::unique_ptr<T> create() { return std::make_unique<T>(); }
};auto circle = GenericFactory<Circle>::create();
✅ 5. 注册式工厂(字符串到对象)
using Creator = std::function<std::unique_ptr<Shape>()>;
static std::unordered_map<std::string, Creator> registry;template<typename T>
struct Registrar {Registrar(const std::string& key) {registry[key] = [] { return std::make_unique<T>(); };}
};// 使用
Registrar<Circle> _circle("circle");
auto shape = registry["circle"](); // 字符串创建对象
✅ 一句话总结
场景 | 用哪种 |
---|---|
简单枚举 | 静态工厂 |
需要扩展 | 工厂方法 |
一族产品 | 抽象工厂 |
编译期决定 | 模板工厂 |
运行时字符串决定 | 注册式工厂 |
一句话:工厂类把 new
藏起来,让 新增类型不改动旧代码(开闭原则)。
3.实现序列化
//实现数据的序列化
bool serialize(const Json::Value &val, std::string &body)
{std::stringstream ss;//先实例化一个工厂类对象Json::StreamWriterBuilder swb;//通过工厂类对象来生产派生类对象std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());int ret = sw->write(val, &ss);if(ret != 0){std::cout << "json serialize failed!\n";return false;}body = ss.str();return true;
}
这段代码实现了一个 JSON 数据的序列化功能,使用 JsonCpp
库将 Json::Value
对象转换为字符串(std::string
)。以下是详细解析:
1. 函数功能
-
输入:
Json::Value
对象(JSON 数据结构)。 -
输出:序列化后的 JSON 字符串(通过引用参数
body
返回)。 -
返回值:
bool
类型,表示序列化是否成功。
2. 关键代码解析
(1) 使用 Json::StreamWriterBuilder
Json::StreamWriterBuilder swb;
-
作用:创建一个 StreamWriter 的工厂类,用于生成
Json::StreamWriter
对象。 -
优势:
-
比直接使用
Json::FastWriter
或Json::StyledWriter
更灵活(可自定义格式化选项)。 -
支持 RAII(通过
std::unique_ptr
自动管理内存)。
-
(2) 创建 Json::StreamWriter
std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());
-
newStreamWriter()
:工厂方法,生成一个StreamWriter
对象。 -
std::unique_ptr
:智能指针,确保StreamWriter
对象自动释放,避免内存泄漏。
(3) 序列化 JSON 到字符串流
int ret = sw->write(val, &ss);
-
sw->write()
:将Json::Value
写入std::stringstream
。-
参数 1:
val
是要序列化的 JSON 数据。 -
参数 2:
&ss
是输出流(这里是字符串流)。
-
-
返回值:成功时返回
0
,失败时返回非零值(但 JsonCpp 的write()
通常不会失败)。
(4) 错误处理
if(ret != 0) {std::cout << "json serialize failed!\n";return false;
}
-
理论上
write()
不会失败,此处是防御性编程(实际可省略)。
(5) 获取结果字符串
body = ss.str();
-
ss.str()
:将std::stringstream
的内容转为std::string
。
4.parse (把一段 JSON 字符串转成内存中的 Json::Value对象
)
在 C++ / JSON 场景里,“parse” 通常指 把一段 JSON 字符串转成内存中的 Json::Value
对象;下面给出 3 行代码 就能用的最简示范,以及常见坑点。
✅ 1. 头文件
#include <json/json.h>
#include <sstream>
✅ 2. 最简解析(字符串 → Json::Value)
std::string jsonStr = R"({"id":1,"name":"Tom","score":[88,92]})";
Json::Value root;
bool ok = Json::parseFromStream(Json::CharReaderBuilder(),std::istringstream(jsonStr),&root, nullptr);
if (!ok) { /* 解析失败 */ }
✅ 3. 常用取值
int id = root["id"].asInt();
std::string name = root["name"].asString();
int first = root["score"][0].asInt();
✅ 4. 从文件解析
Json::Value cfg;
std::ifstream f("config.json");
Json::parseFromStream(Json::CharReaderBuilder(), f, &cfg, nullptr);
⚠️ 5. 常见错误
-
忘记
#include <json/json.h>
-
使用旧 API
Json::Reader().parse
(已废弃,改用parseFromStream
) -
数组越界(先
root["score"].isArray()
再访问)
✅ 一句话
Json::parseFromStream
就是 “把 JSON 字符串 → Json::Value” 的标准接口,解析后按 root["key"]
取值即可
5.实现反序列化
bool unserialize(std::string &body, Json::Value &val)
{//实例工厂化对象Json::CharReaderBuilder crb;//生产CharReader对象std::string errs;std::unique_ptr<Json::CharReader> cr(crb.newCharReader());bool ret = cr->parse(body.c_str(), body.c_str() + body.size(), &val, &errs);if(ret == false){std::cout << "json unserialize failed: " << errs << std::endl;\return false;}return true;
}
这段代码实现了一个 JSON 字符串的反序列化功能,使用 JsonCpp
库将字符串(std::string
)解析为 Json::Value
对象。以下是详细解析:
1. 函数功能
-
输入:JSON 格式的字符串
body
。 -
输出:解析后的
Json::Value
对象(通过引用参数val
返回)。 -
返回值:
bool
类型,表示反序列化是否成功。
2. 关键代码解析
(1) 使用 Json::CharReaderBuilder
Json::CharReaderBuilder crb;
-
作用:创建一个 CharReader 的工厂类,用于生成
Json::CharReader
对象。 -
优势:
-
比直接使用
Json::Reader
(旧版)更灵活,支持自定义解析选项。 -
配合
std::unique_ptr
实现自动内存管理。
-
(2) 创建 Json::CharReader
std::unique_ptr<Json::CharReader> cr(crb.newCharReader());//newCharReader():工厂方法,生成一个 CharReader 对象。
//std::unique_ptr:智能指针,确保 CharReader 对象自动释放。
(3) 解析 JSON 字符串
bool ret = cr->parse(body.c_str(), body.c_str() + body.size(), &val, &errs);
-
parse()
参数:-
body.c_str()
:字符串起始地址。 -
body.c_str() + body.size()
:字符串结束地址。 -
&val
:输出参数,存储解析后的 JSON 数据。 -
&errs
:输出参数,存储错误信息(如果解析失败)。
-
-
返回值:成功返回
true
,失败返回false
。
6.R
R
是 C++11 引入的“原始字符串字面量”标记,用来 取消转义字符的影响,让 JSON、正则、路径 等字符串所见即所得。
✅ 语法
R"(原始内容)"
-
以
R"
开头 -
以
"
结尾 -
中间 任何字符(包括
\
"
换行符)都不转义
✅ 对比示例
写法 | 结果 |
---|---|
"C:\\Program Files\\A" | 需要双反斜杠 |
R"(C:\Program Files\A)" | 直接写单斜杠即可 |
✅ 在你的 JSON 例子
std::string str = R"({"姓名":"小黑", "年龄": 19, "成绩":[32, 45, 56]})";
-
无需对
"
或\
转义 -
编译器会原样保留花括号、引号、中文。
✅ 一句话
R"()"
就是 “所见即所得” 的字符串,写 JSON、正则、路径时最省心。
7.测试与实现汇总
#include <iostream>
#include <string>
#include <sstream>
#include <memory>
#include <jsoncpp/json/json.h>//实现数据的序列化
bool serialize(const Json::Value &val, std::string &body)
{std::stringstream ss;//先实例化一个工厂类对象Json::StreamWriterBuilder swb;//通过工厂类对象来生产派生类对象std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter());int ret = sw->write(val, &ss);if(ret != 0){std::cout << "json serialize failed!\n";return false;}body = ss.str();return true;
}//实现json字符串的反序列化
bool unserialize(std::string &body, Json::Value &val)
{//实例工厂化对象Json::CharReaderBuilder crb;//生产CharReader对象std::string errs;std::unique_ptr<Json::CharReader> cr(crb.newCharReader());bool ret = cr->parse(body.c_str(), body.c_str() + body.size(), &val, &errs);if(ret == false){std::cout << "json unserialize failed: " << errs << std::endl;\return false;}return true;
}
int main()
{const char* name = "小明";int age = 18;const char* sex = "男"; float score[3] = {88, 77.5, 66};//序列化Json::Value student;student["姓名"] = name;student["年龄"] = age;student["性别"] = sex;student["成绩"].append(score[0]);student["成绩"].append(score[1]);student["成绩"].append(score[2]);Json::Value fav;fav["书籍"] = "西游记";fav["运动"] = "打篮球";student["爱好"] = fav;std::string body;serialize(student, body);std::cout << body << std::endl;//反序列化std::string str = R"({"姓名":"小黑", "年龄": 19, "成绩":[32,45,56]})";Json::Value stu;bool ret = unserialize(str, stu);if(ret == false)return -1;std::cout << "姓名:" << stu["姓名"].asString() << std::endl;std::cout << "年龄:" << stu["年龄"].asInt() << std::endl;int sz = stu["成绩"].size();for(int i = 0; i < sz; i++){std::cout << "成绩:" << stu["成绩"][i].asFloat() << std::endl;}return 0;
}//g++ -std=c++11 jsoncpp.cpp -o json -ljsoncpp