如何以多态方式无限嵌套对象

How to infinitely nest an object polymorphically

我有一个 Config class,其中包含 <string, string> map 数据,用于保存配置键和值。有时,我不知道在编译时什么时候,我希望能够访问该对象内的一个键作为该对象的另一个(子)实例 - 我希望能够在理论上无限嵌套.

未解析的数据看起来像这样

someKey     = someVal
keysnkrates = "itsastring"
# comments

keyConfig = (
    subKey  = 1
    another = 3.14159
    subKeyConfig = (
        ...inf...
    )
)

otherVals = ...

我怎样才能在不诉诸 hack-y 类 C 方法的情况下解析这样的东西?我不想处理原始指针,也不想处理空值,但是我想出的唯一解决方案涉及添加指向 Config class 的指针,如果它是 !nullptr 然后它是一个子配置对象。

如果你这样写:

struct foo {
    int a, b, c;
    struct bar nested_struct;
}

然后每次分配一个新的 foo 时,您就为三个整数 分配了足够的 space 整个 bar 对象,不管它有多大。

您不能 "infinitely" 以这种方式嵌套 structs/classes,因为您的计算机没有无限内存。

我不知道你所说的 raw 指针是什么意思,但是如果你不想使用指针和 NULL 创建自己的链接数据结构,那么你可能应该使用标准库中的一些预定义 容器 class。†

我不是 C++ 程序员,所以我不知道有哪些 classes 和库可用,但我确定它们在那里。


†(编辑)不是 可能。您编写的每一行代码最终都会成为一种负担。如果您正在编写真正的(商业)软件,那么编写比解决手头问题绝对需要的行更多的行总是错误的。如果有一个库可以满足您的需求,那么您应该使用它。

有时,问题的最佳解决方案取决于具体问题的细节。在您的情况下,这些细节之一是您最终希望如何使用生成的数据结构(哪种形式的查询应该 work/work 快?)。

除此之外,如果您注意到问题的特定属性并以机会主义的方式利用它们,有时 "shortcuts" 是可能的。

虽然输入数据的结构显然暗示着树状数据结构,但一种可能的机会主义捷径是,如果子配置数据中的键在所有级别上出现的所有键的集合中是唯一的。然后你可以简单地使用地图并依赖没有同义词键。当然,这会从您的数据中删除结构信息,您需要决定是否可以接受。

扩展这个想法,有时您还可以通过重新考虑您将什么用作地图的键来避免实现树:现在您使用字符串。它也可以是像 (key,level) 这样的元组,或者是层次结构中的键与 "path" 的串联(例如 "top/topchild/topchildchild")。同样,这取决于您稍后将如何处理数据,如果这对您来说是一种可行的方法。

最后同样重要的是,如果您找到一种方法将 push_back() 新条目放入数组并使用数组索引来表示 parent/child 关系。

只使用普通的STL贴图。您认为(至少)某些 JSON 和 XML 解析器在 C++ 中如何工作?

struct Config{
  Data data;
  std::map <std::string,Config> children;
}

现在内嵌值随心所欲:

Config config;
config.children["My Inner Config "] = Config(<my data>);
config.children["My Inner Config "].children["My inner inner config"] = Config(<more data>);

一种稍微复杂的方法(比公认的答案)是使用 boost::variant 来表示可能的 children 和每个节点的可能数据。

struct Node;

typedef boost::variant<int, std::string, boost::recursive_wrapper<Node>> Value;

struct Node {
    std::map<std::string, Value> children;
};

或者类似的东西。 这很好,因为如果你添加几种不同的类型作为有效值,你不需要在你的各种结构中使用 10 个不同的 children,这会在你想要支持的方法中生成很多样板代码.