IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> JSON for Modern C++(原 nlohmann json)再封装之toJson -> 正文阅读

[C++知识库]JSON for Modern C++(原 nlohmann json)再封装之toJson

JSON for Modern C++?可以说是非常摩登的一个C++ json 库了,支持容器化操作(push_back等操作),支持从 stl 容器(vector ,map)创建 json。具体用法就不赘述了,打开文章开头的链接自行查看即可,非常简单。

这篇文章主要是通过自定义树形结构,对这个库进行进一步封装,以期待实现动态的 json 序列化和反序列化。

树形结构擅于组织具有节点关系的动态数据,也适合递归,和 json 的结构不能说很像,只能说非常适合json,所以用它来做与 json 交互的数据结构。

首先创建一个树形结构的基本节点,作为所有节点对象的父类。由于动态树形对象的析构,需要进行链式动态析构(父节点delete子节点),如果在栈上申请对象的话是不行的,所以把析构函数放到 protected 下,这样就不能在栈上创建这个对象了。所有继承这个节点的类,都要把析构函数放到 protected 下。

#include <iostream>
#include <nlohmann/json.hpp>

using namespace nlohmann;

class Node {
protected:
    //节点名称
    std::string nodeName;
    //本节点对应的json
    json j;
    //子节点们
    std::vector<Node*> nodes;
public:
    //把本类序列化成json的方法,由子类实现
    virtual void toJson(json& j, std::string& errMsg) {

    }
    //把json反序列化成本类的方法,由子类实现
    virtual void toNode(json& j, std::string& errMsg) {

    }

    //添加子节点
    void addNode(Node* node) {
        nodes.push_back(node);
    }

    //把子节点序列化成json
    void childNodesToJson(json& j) {
        for (Node* node : nodes) {
            json jnode;
            std::string err;
            node->toJson(jnode, err);
            j[node->nodeName] = jnode;
        }
    }

    //创建一个子节点类型的节点
    template<typename T>
    static T* create() {
        return new T;
    }

    //delete本节点
    template<typename T>
    T* release() {
        delete this;
        return nullptr;
    }


    void setNodeName(std::string nodeName) {
        this->nodeName = nodeName;
    }

protected:
    Node() {

    }
    //由于析构时需要动态的,链式的析构,所以不允许在栈上申请对象
    virtual ~Node() {
        for (Node* node : nodes) {
            node->release<Node>();
        }
    }
};

为了方便,再写一个代表节点数组的类 NodeArray,来表示json中的数组结构,它既是 Node* 的数组,本身又是一个 Node*

class NodeArray :public std::vector<Node*>, public Node {
public:
    NodeArray(std::string name) {
        nodeName = name;
    }
    NodeArray() {}
    void toJson(json& j, std::string& errMsg) override{
        int size = this->size();
        
        for (int i = 0; i < size; i++) {
            json jchild;
            (*this)[i]->toJson(jchild, errMsg);
            j.push_back(jchild);
        }
    }
    void toNode(json& j, std::string& errMsg) override {

    }
protected:
    ~NodeArray() {
        for (Node* node : *this) {
            node->release<Node>();
        }
    }
};

有了这两个基本的类,就可以进行子类化开发了,比如有这样一个json,里面嵌套了一个数组

    "ship": {
        "cargo": [
            {
                "good": "FUEL",
                "quantity": 23,
                "totalVolume": 23
            },
            {
                "good": "FUEL",
                "quantity": 23,
                "totalVolume": 23
            },
            {
                "good": "FUEL",
                "quantity": 23,
                "totalVolume": 23
            }
        ],
        "class": "MK-I",
        "id": "ckon84fo20196vinzktdlvdlv",
        "location": "OE-PM-TR",
        "manufacturer": "Jackshaw",
        "maxCargo": 50,
        "plating": 5,
        "spaceAvailable": 27,
        "speed": 1,
        "type": "JW-MK-I",
        "weapons": 5,
        "x": 21,
        "y": -24
    }

为了生成一个形如这样的json,来子类化 Node,首先创建一个描述数组中的元素

? ? ? ? ? ? {
? ? ? ? ? ? ? ? "good": "FUEL",
? ? ? ? ? ? ? ? "quantity": 23,
? ? ? ? ? ? ? ? "totalVolume": 23
? ? ? ? ? ? },

的类,代码如下:

class cargo :public Node {
public:
    std::string good = "FUEL";
    int quantity = 17;
    int totalVolume = 17;
    void toJson(json& j, std::string& errMsg) override {
        j["good"] = good;
        j["quantity"] = quantity;
        j["totalVolume"] = totalVolume;
        childNodesToJson(j);
    }
protected:
    ~cargo() {

    }
};

然后创建一个描述ship的类,代码如下:

class ship:public Node {
public:
    NodeArray *cargos = new NodeArray();
    MyNode *mynode = new MyNode();
    ship(){
        cargos->push_back(new cargo());
        cargos->push_back(new cargo());
        cargos->push_back(new cargo());
        cargos->setNodeName("cargos");//To be a child node, NodeArray should have a name 
        addNode(cargos);//addNode后Node会由父类析构函数析构
        addNode(mynode);//addNode后Node会由父类析构函数析构
        //否则要在本类析构函数析构

    }
    void toJson(json& j, std::string& errMsg) override {
        json jcargos;
        cargos->toJson(jcargos,errMsg);
        j["cargos"] = jcargos;
        childNodesToJson(j);
        j["class"] = "MK-I Jackshaw OE-PM";
    }
protected:
    ~ship() {
    
    }
};

最后写个测试程序测试一下

int test() {  
    json jship;
    std::string err;

    ship* myship = new ship();
    myship->toJson(jship,err);
    myship = myship->release<ship>();

    json js;
    js["ship"] = jship;
   
    std::cout << js.dump(4);
    return 0;
}

输出为

{
    "ship": {
        "cargos": [
            {
                "good": "FUEL",
                "quantity": 17,
                "totalVolume": 17
            },
            {
                "good": "FUEL",
                "quantity": 17,
                "totalVolume": 17
            },
            {
                "good": "FUEL",
                "quantity": 17,
                "totalVolume": 17
            }
        ],
        "class": "MK-I Jackshaw OE-PM"
    }
}

写在最后:

做这个封装的目的在于,对于 json 的每个节点都可能动态变化的情况下,可以灵活的增加一个或大或小,深度或深或浅的预定义节点(或根据预定义节点组合的新节点),而不用修改代码。非常适合编辑 json。

而结构简单的小json,还是使用 JSON for Modern C++ 直接定义更方便。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-18 17:22:53  更:2022-04-18 17:25:00 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:40:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码