我决定用 C++ 编写一个 json 解释器来练习。理想情况下,我希望能够将它设置在一个包含地图、向量和相关值类型的树状容器中,以便我可以按照 json 的实际结构方式进行访问。例如,给出以下 JSON 示例(来自 json.org):
JSON
{
"menu": {
"id": "file",
"value": "File",
"popup": {
"menuitem": [
{"value": "New", "onclick": "CreateNewDoc()"},
{"value": "Open", "onclick": "OpenDoc()"},
{"value": "Close", "onclick": "CloseDoc()"}
]
}
}}
C++
jsonobject["menu"]["id"] // returns std::string "file"
jsonobject["menu"]["popup"]["menuitem"] // returns std::vector of std::maps
jsonobject["menu"]["popup"]["menuitem"][0]["value"] // returns std::string "New"
在上面的示例中,我的第一个问题来自容器内的混合类型。例如,在上面的 json 中,“menu”将是一个 std::map,但我不能拥有“id”和“popup”键,因为一个返回一个字符串,另一个返回一个向量。
为了解决这个问题,我决定创建从无类型基类继承的包装模板类。假设这将提供对值的多态访问。问题是我做不到。这是一些代码来显示我到目前为止所拥有的内容:
#include <string>
#include <map>
#include <vector>
class NodeBase {};
template <typename T>
class Node : public BaseNode {};
typedef std::map<std::string, BaseNode*> JSONObject;
template <>
class Node<JSONObject> : public BaseNode {
public:
JSONObject value;
BaseNode* operator[](const std::string key){(value.find(key) != value.end) ? return value[key] : return nullptr}
};
typedef std::vector<BaseNode*> JSONArray;
template <>
class Node<JSONArray> : public BaseNode {
public:
JSONArray value;
BaseNode* operator[](const uint index) {(index < value.size()) ? return value[index] : return nullptr}
};
template <typename T>
class Node : public BaseNode {
public:
T value;
};
class RootNode {
Node<JSONObject> value;
};
int main(void) {
RootNode root;
root.insert(std::pair<std::string, BaseNode*>("menu", new Node<JSONObject>)
// problem!
// cannot use following code, because BaseNode* does not have access to value :'<
root["menu"].insert(..)
}
所以我想我的问题是,我该如何进行这项工作?我是在正确的道路上,但无法从经验中看到解决方案,还是这种设计与 C++ 根本不兼容?