不要尝试根据每个节点的父节点数量来强类型化,而是将代码组织为树结构:
class Element
{
public:
std::string Name;
std::map<std::string, std::string, std::less<std::string> > Attributes;
std::list<Element> Children;
};
您的公共界面可能看起来与此大不相同。我只是想展示一般的类型布局。
您实际上并不需要节点或属性功能,除非您需要在集合中与元素一起迭代它们。这对于 XML DOM 库来说是一个有用的功能,但如果您只是想创建一个数据结构,则不必完全遵循 DOM 设计。
事实上,如果你只是想要一个通用的数据结构,你可能只需要一个属性包:
#include<map>
#include<string>
#include<iostream>
class PropertyBag;
typedef std::map<std::string, PropertyBag> PropertyMap;
class PropertyBag : public PropertyMap
{
public:
PropertyBag(const std::string& value)
: value(value)
{
}
PropertyBag& operator=(const std::string& value)
{
this->value = value;
return *this;
}
operator std::string& () { return value; }
private:
std::string value;
friend PropertyMap::mapped_type& PropertyMap::operator[](const PropertyMap::key_type&);
PropertyBag() { }
};
void SomeFunction(const std::string& value)
{
std::cout << value << "\n";
}
int main(int argc, char* argv[])
{
PropertyBag config("configuration root");
config["child1"] = "value1";
config["child1"]["subchild1"] = "value2";
SomeFunction(config["child1"]);
SomeFunction(config["child1"]["subchild1"]);
return 0;
}
就语法而言,您也可以尝试重载operator() 和/或链接方法来解决问题:
PropertyBag& SomeMethod(const std::string& someParam)
{
// do something here...
return *this;
}
PropertyBag& operator()(const std::string& p1, const std::string& p2)
{
// ...
return *this;
}
// ...
Configuration config1("root")
.SomeMethod("p1")
.SomeMethod("p2");
Configuration config2("root")
("Something", "blah")
("sizzle", "V2");
我想文本/代码重复越少越好。您可以让代码越接近 JSON 或 YAML 之类的语法越好。
一旦 c++0x 出现,您可能会有更简单的选择。您还可以查看 boost::assign library 以获得用于数据结构的简单初始化语法。
您还可以在boost::any library 中查找可以用作值的数据类型,而不是字符串(支持插入任何值的类型安全方法,只要将其提取为相同类型即可)。