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

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 → stringstd::string s = std::to_string(123); 或 stringstream ss; ss << 123; ss.str();
string → intstringstream 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

    • 参数 1val 是要序列化的 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

  RC++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 

 

http://www.dtcms.com/a/311761.html

相关文章:

  • 【Android】RecyclerView实现新闻列表布局(1)适配器使用相关问题
  • 【Leetcode】2561. 重排水果
  • 【Django】-6- 登录用户身份鉴权
  • 知识随记-----Qt 实战教程:使用 QNetworkAccessManager 发送 HTTP POST
  • 面试小总结
  • 解决技术问题思路
  • STM32学习记录--Day6
  • Spring 中 Bean 的生命周期
  • 知识蒸馏 - 基于KL散度的知识蒸馏 HelloWorld 示例
  • Linux网络编程【UDP网络通信demon】
  • 网页操作自动化解决方案:如何用Browser-Use+CPolar提升企业运营效率
  • React ahooks——副作用类hooks之useThrottleFn
  • 【智能体cooragent】新智能体创建相关代码解析
  • 双网卡UDP广播通信机制详解
  • 海洋大地测量基准与水下导航系列之九我国海洋PNT最新技术进展(下)
  • P13014 [GESP202506 五级] 最大公因数
  • 使用WSL2开发zephyr
  • 重型机械作业误伤预警响应时间缩短80%!陌讯多模态识别算法在工程现场的应用优化
  • 音频3A处理简介之AGC(自动增益控制)
  • RHCE认证题解
  • 自动驾驶中的传感器技术13——Camera(4)
  • 知识蒸馏 - 最小化KL散度与最小化交叉熵是完全等价的
  • stm32103如果不用32k晶振,那引脚是悬空还是接地
  • C++入门基础(三):const引用、指针和引用的关系、inline(修饰内联函数)替代宏、nullptr代替null
  • 使用docker运行vite项目
  • C++ vector底层实现与迭代器失效问题
  • 深入 Go 底层原理(十五):cgo 的工作机制与性能开销
  • 【深度学习】【三维重建】windows11环境配置PyTorch3d详细教程
  • Flutter开发 初识目录结构
  • 自动布局视图来实现聊天室的界面