大同市网站建设_网站建设公司_Redis_seo优化
2026/1/19 20:52:45 网站建设 项目流程

QJson (Qt) vs. nlohmann/json (现代 C++)

在 C++ 开发中,JSON 的处理方式主要分为两类:基于 DOM 树的操作(如 Qt 的 QJson)和 基于对象映射的操作(如 nlohmann/json)。

核心概念对比

特性 QJson (Qt 框架) nlohmann/json (现代 C++)
库类型 Qt 核心模块的一部分,强依赖 Qt 完整开发环境 Header-only(单头文件),无任何外部依赖,开箱即用
操作风格 显式容器转换 (Object -> Map) 类原生对象操作
(像操作 C++ 原生结构体/数组一样操作 JSON 数据)
序列化/反序列化 手动逐个键值对调用接口提取/插入数据 自动序列化 (通过宏映射结构体)
语法糖 & 语法简洁度 语法糖较重,使用时需要频繁调用类型转换方法
.toObject().toArray().toString().toInt()
语法糖极度轻量优雅,原生支持 C++ 初始化列表

使用示例

1. QJson 构建JSON对象(手动+频繁类型转换)

QJsonObject jsonObj;
jsonObj.insert("name", QJsonValue(QString("QtJson")));
jsonObj.insert("version", QJsonValue(6.7));
jsonObj.insert("is_valid", QJsonValue(true));QJsonArray arr;
arr.append(QJsonValue(1));
arr.append(QJsonValue(2));
jsonObj.insert("nums", QJsonValue(arr));// 读取时还需要显式转换
QString name = jsonObj["name"].toString();
int num = jsonObj["nums"].toArray()[0].toInt();

2. nlohmann/json 构建JSON对象(类原生+初始化列表)

#include "nlohmann/json.hpp"
using json = nlohmann::json;// 原生初始化列表写法,无任何转换调用,像写结构体一样
json jsonObj = {{"name", "nlohmann_json"},{"version", 3.11.2},{"is_valid", true},{"nums", {1, 2, 3}}
};// 读取时类原生访问,无需转换
std::string name = jsonObj["name"];
int num = jsonObj["nums"][0];

3. nlohmann/json 结构体自动序列化(核心优势)

// 定义普通C++结构体
struct User {std::string name;int age;std::vector<int> scores;
};
// 宏一键映射,完成序列化规则绑定
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(User, name, age, scores)// 自动序列化/反序列化
User u{"Tom", 20, {90, 85}};
json j = u; // 结构体 → JSON,自动完成
User u2 = j; // JSON → 结构体,自动完成

对比XML

XML必须严格遵循标签结构,且解析时通常需要处理节点、属性和文本的层级关系。

<!-- 数据表示 -->
<User id="1001"><Name>Alice</Name><Age>25</Age><Tags><Item>Vision</Item><Item>C++</Item></Tags>
</User>
// C++ 解析 XML 的伪代码 
tinyxml2::XMLDocument doc;
doc.LoadFile("user.xml");
auto* user = doc.FirstChildElement("User");
const char* name = user->FirstChildElement("Name")->GetText();
int age = user->FirstChildElement("Age")->IntText();
// 获取列表需要循环遍历节点
std::vector<std::string> tags;
for (auto* item = user->FirstChildElement("Tags")->FirstChildElement("Item"); item != nullptr; item = item->NextSiblingElement("Item")) {tags.push_back(item->GetText());
}

XML 的痛点:结构冗余(每个数据都要写开头和结尾标签);解析复杂(通常需要逐级遍历节点,或者使用复杂的 XPath);类型缺失(所有内容本质都是字符串,需手动转换)。

nlohmann/json 深度解析

nlohmann/json 被誉为 "JSON for Modern C++",其核心优势在于极其直观的语法,几乎让你感觉在写 Python。

1.基础用法与 CRUD

该库重载了 [] 和 << 等操作符,使得操作 JSON 像操作 std::map 一样简单。

#include <nlohmann/json.hpp>
using json = nlohmann::json;// 1. 创建 JSON 对象 (使用初始化列表)
json j = {{"pi", 3.141},{"name", "Niels"},{"answer", {{"everything", 42}}},{"list", {1, 0, 2}}
};// 2. 增加/修改
j["new_key"] = "new_value";// 3. 查询
if (j.contains("name")) {std::string name = j["name"];
}// 4. 序列化
std::string s = j.dump(4);

2.进阶:非STL容器/第三方库支持 (adl_serializer)

当你使用第三方库(如 OpenCV、Qt)时,由于无法修改它们的源码来添加宏,需要通过特化adl_serializer来告诉 json 库如何处理这些类型。

A.处理 OpenCV 类型 (cv::Point3f)

namespace nlohmann {template <>struct adl_serializer<cv::Point3f> {static void to_json(json& j, const cv::Point3f& pt) {j = json::array({pt.x, pt.y, pt.z});}static void from_json(const json& j, cv::Point3f& pt) {pt.x = j[0].get<float>();pt.y = j[1].get<float>();pt.z = j[2].get<float>();}};
}

B. 处理 Qt 常用类型 (QString, QDateTime, QVariant)

  • QString: 自动转换 Qt 的 UTF-16 字符串与标准 std::string。

  • QDateTime: 将日期时间自动序列化为符合 ISO 8601 标准的字符串(如 2023-10-27T10:00:00.000)。

  • QVariant: 能够根据存储的实际类型(int, bool, double, Map 等)动态选择 JSON 类型。

namespace nlohmann {// QString 序列化支持template <>struct adl_serializer<QString> {static void to_json(json& j, const QString& str) {j = str.toStdString();}static void from_json(const json& j, QString& str) {str = QString::fromStdString(j.get<std::string>());}};// QDateTime 序列化支持template <>struct adl_serializer<QDateTime> {static void to_json(json& j, const QDateTime& dt) {j = dt.toString(Qt::ISODateWithMs).toStdString();}static void from_json(const json& j, QDateTime& dt) {dt = QDateTime::fromString(QString::fromStdString(j.get<std::string>()), Qt::ISODateWithMs);}};
}

3.核心功能:自定义结构体映射 (宏)

  1. 侵入式定义 (在结构体内): 适合可以修改结构体源码的情况。使用 NLOHMANN_DEFINE_TYPE_INTRUSIVE 宏直接在类定义中注册成员。
struct Person {QString name; // 配合 3.2 中的 adl_serializer 即可直接使用 QStringint age;NLOHMANN_DEFINE_TYPE_INTRUSIVE(Person, name, age)
};
  1. 非侵入式定义 (在结构体外)
    适合无法修改源码的第三方结构体或库。使用 NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE 宏在类定义外部进行注册。
// 假设这是一个外部库定义的结构体,无法修改其 header 文件
struct ExternalUser {std::string id;double score;
};// 在全局命名空间或对应的命名空间内进行注册
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(ExternalUser, id, score)

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询