我一直在尝试解决这个问题,也许我已经盯着它太久了?
无论如何,手头的问题是找到一种好的方法来表示JSON在C++中,但请注意,在您继续阅读之前,请注意,我不想使用能够处理JSON的库,所以我想用裸的C或C++(C++11可以),没有boost,没有libjson。我知道它们,但由于本问题范围之外的原因,我不能/不会添加依赖项。
既然清楚了这一点,让我告诉你一些关于问题以及我迄今为止尝试过的内容。
问题是找到一种好的方法来表示JSON在C++中,这有点棘手的原因是JSON的类型非常松散,而C++则非常强类型。考虑一下JSON,从类型上来说,JSON真正具备什么能力?
- 数字(例如
42
或3.1415
) - 字符串(例如
"my string"
) - 数组(例如
[]
或[1,3.1415,"my string]
) - 对象(例如
{}
或{42, 3.1415, "my string", [], [1,3.1415, "my string]}
这意味着有两种“原始”类型,即数字和字符串,以及两种容器类型数组和对象。原始类型非常直观,而容器类型在C/C++中变得棘手,因为它们可以并且可能包含不同类型的元素,因此任何语言内置类型都不足以胜任,数组无法容纳不同类型的元素。这也适用于STL类型(列表、向量、数组等)(除非它们具有多态相等性)。
因此,JSON中的任何容器都可以容纳任何类型的json类型,这就是全部内容。
我尝试过的原型或尝试过的方法以及为什么行不通 我的第一个天真的想法是只使用模板,因此我设置了一个json对象或json节点类型,然后使用模板来决定其中的内容,因此它将具有以下结构:
template <class T>
class JSONNode {
const char *key;
T value;
}
虽然这看起来很有前途,但当我开始使用它时,我意识到当我尝试将节点排序到容器类型(例如数组、向量、无序映射等)中时遇到了问题,因为它们仍然想知道那个JSONNode的类型! 如果一个节点被定义为
JSONNode<int>
而另一个节点被定义为 JSONNode<float>
那么将会有问题将它们放在一个容器中。所以我不再关心将它们保留在容器中,我更愿意让它们自我感知或称之为添加指向下一个节点的指针,但是要找出节点的类型变得棘手,就在这里,我开始考虑多态性。
多态性 让我们制作一个虚拟的
JSONNode
并实现一个 JSONNumberNode,JSONStringNode,JSONArrayNode
和 JSONObjectNode
类型, 它们将很好地适应我想要的任何容器,使用多态性使它们都成为JSONNodes。代码示例可能也是有用的。
class JSONNode {
public:
const char *key;
//?? typed value, can't set a type
};
class JSONNumberNode : public JSONNode {
public:
int value;
}
class JSONStringNode : public JSONNode {
public:
const char *value;
}
起初我认为这是正确的方法。但当我开始考虑如何处理值时,我意识到我无法访问该值,即使我编写了一个特定的函数来检索该值,它会返回什么?
所以,我确实有具有不同类型值的对象,但如果没有首先将其转换为适当的类型,我无法真正访问它们,因此我可以执行
dynamic_cast<JSONStringNode>(some_node);
,但我怎么知道要将其转换为什么?RTTI?那么在那一点上,我感觉变得太过复杂了,我想我可能能够使用typeof或decltype来确定需要强制转换的内容,但并未成功。POD类型 因此,我尝试了不同的方法,认为也许我实际上可以通过pod方式实现这一点。然后,我将设置“value”部分为“void *”,并尝试保留一些“union”来跟踪类型。但是,我遇到了与之前相同的问题,即如何将数据强制转换为类型。
我感到有必要解释一下为什么我没有深入研究过POD的原因。
因此,如果有人对如何在C++中表示JSON具有智能解决方案,并且给出了这些信息,我将非常感激。
boost::variant
。如果您想重新发明它,请至少检查其设计。 - zch