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.14
    std::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 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pipip.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值