JSON (JavaScript Object Notation) 作为一种轻量级的数据交换格式,在现代软件开发中扮演着重要角色。在 C++ 开发中,nlohmann/json 库因其易用性和灵活性而广受欢迎。本文将通过实例介绍如何使用这个强大的库进行 JSON 数据的序列化和反序列化操作。
环境准备
首先,我们需要配置项目环境。这里使用 CMake 作为构建系统:
cmake_minimum_required(VERSION 3.15 FATAL_ERROR)
project("nlohmann_json_test" CXX)find_package(nlohmann_json CONFIG REQUIRED)set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)add_executable(nlohmann_json_test nlohmann_json_test.cpp)
target_link_libraries(nlohmann_json_test PRIVATE nlohmann_json::nlohmann_json)
数据结构定义
在示例中,我们定义了三个主要的数据结构:
struct Address {std::string street;std::string number;std::string postcode;NLOHMANN_DEFINE_TYPE_INTRUSIVE(Address, street, number, postcode);
};struct Person {std::string name;int age;std::vector<Address> addresses;NLOHMANN_DEFINE_TYPE_INTRUSIVE(Person, name, age, addresses);
};struct ApiResult {bool success;std::string message;json data;NLOHMANN_DEFINE_TYPE_INTRUSIVE(ApiResult, success, message, data);
};
这里的关键是使用 NLOHMANN_DEFINE_TYPE_INTRUSIVE
宏,它自动为我们的结构体生成序列化和反序列化的代码。这大大简化了 JSON 转换过程,无需手动编写转换逻辑。
JSON 序列化示例
让我们看看如何将 C++ 对象序列化为 JSON:
Person person = {"John Doe",20,{{"Main St", "123", "12345"},{"Second St", "456", "67890"}}
};// 序列化为 JSON
json j = person;
std::cout << j.dump(4) << std::endl;
序列化结果:
{"addresses": [{"number": "123","postcode": "12345","street": "Main St"},{"number": "456","postcode": "67890","street": "Second St"}],"age": 20,"name": "John Doe"
}
JSON 反序列化示例
同样简单,我们可以将 JSON 字符串反序列化为 C++ 对象:
json j2 = R"({"name": "Jane Doe","age": 25,"addresses":[{"street":"jiangxia","number":"258","postcode":"54321"},{"street":"wuchang","number":"369","postcode":"12345"}]}
)"_json;Person person2;
j2.get_to(person2);
API 响应封装示例
在实际开发中,我们经常需要处理 API 响应。这里展示了如何使用 ApiResult
结构体封装不同类型的响应:
// 成功响应,携带数据
ApiResult ar1;
ar1.success = true;
ar1.message = "success";
ar1.data = person;
json jar1 = ar1;// 错误响应
ApiResult ar2;
ar2.success = false;
ar2.message = "A fatal error has occurred";
ar2.data = nullptr;
json jar2 = ar2;
这将产生如下 JSON 输出:
成功响应:
{"data": {"addresses": [...],"age": 20,"name": "John Doe"},"message": "success","success": true
}
错误响应:
{"data": null,"message": "A fatal error has occurred","success": false
}
主要特点和优势
- 简单直观的 API:通过
NLOHMANN_DEFINE_TYPE_INTRUSIVE
宏,可以轻松实现序列化和反序列化。 - 类型安全:编译时类型检查,避免运行时错误。
- 灵活的数据处理:支持复杂的嵌套结构和各种数据类型。
- 现代 C++ 特性支持:与 C++11 及以上版本完全兼容。
- 错误处理:提供清晰的错误信息和异常处理机制。
注意事项
- 使用
NLOHMANN_DEFINE_TYPE_INTRUSIVE
时,需要确保所有成员变量都是可序列化的。 - 在处理大型 JSON 数据时,要注意内存使用。
- 对于非字符串类型的键,需要特别处理。
- C++20 提供了更简洁的结构体初始化语法,但要注意编译器支持情况。