比如说,我有从CPrimus
继承的类CSecundus
,CTertius
和CParentis
,我想实现一个对象树,其中有叶子(节点?)可以是任何一个派生类的实例,例如:
在C ++中实现此树的最佳方法是什么,以及可能需要对类进行哪些修改才能支持它?
(*)我会将“最佳”的定义留给社区,无论是“最快”,“最有效”,“最漂亮”,还是您喜欢的任何内容。我个人偏好简单而有效,但如果获得收益,我愿意牺牲简单性。此外,如果您要建议BGL,请尝试举例,或者至少链接到文档或文档的特定部分,以解释如何实现树。
修改
由于这个问题有点过于笼统,我将给出一个潜在的用例。在Linux中,文件系统(通常)将位于裸分区,MD阵列或LVM逻辑卷的顶部。假设我希望我的类表示这些结构并存储关于它们的元数据(设备名称,大小,uuid等等)以供以后检索,并且基类具有一组用于刷新和检索元数据的虚函数。
现在,假设我的系统有一个像这样的磁盘布局:
我如何将其表示为C ++数据结构?
答案 0 :(得分:3)
啊,是的,多个问题。
<强> 1。容器没有标准的容器,你可以自己滚动,但要完成它需要做很多工作。我找到的最好的东西是Tree Container Library - 免费且记录完备。我没有把它放在重负荷下,但它看起来很“有效”。
<强> 2。多态容器 - 也就是说,不同类型的容器作为元素 - 在C ++中有点痛苦。但是,由于您已经拥有共享基类,因此您有很多选择。
CParentis
中的虚拟方法。static_cast
:您将项目存储为CParentis *
(或更好,智能指针)。如果对于CParentis *
你知道它实际是什么类型,你可以使用static_cast dynamic_cast
:与上面相同,但dynamic_cast将使用运行时类型信息,您可以“探测”不同类型。然而,根据类层次结构和编译器(游戏开发人员讨厌它,因为在大多数编译器下它无法处理渲染场景的数千个对象),它可能会很慢。boost::any
:这是一段来自boost的精彩代码,可让您存储任何类型的代码,并在以后找出要求。像dynamic_cast一样,但不需要共享基类。但是,需要额外的分配 - 可能是数百万个对象的问题。boost::variant
:喜欢boost:any,但是对于一组预定义的类型,开销会减少。如果使用static_cast路由,则需要在类中添加类型标识符(或使用typeof)。但是,切换类型以实现特定处理是代码气味,因为它与所涉及的类的数量/对象的数量严重不同。更好的扩展解决方案是一个共享的抽象基类(当事先知道操作时)或访问者模式(当你需要稍后抛出其他操作时)。
最后,最小的:如果房间里有comp sci专业,则永远不要叫那棵树。 Hel将用他的电子书阅读器砸你的头,解释它是一个有针对性的acyclig图,然后抱怨你打破了他的玩具(至少,这就是我想象我们的comp sci家伙做的,如果他有一本电子书读者...)
答案 1 :(得分:2)
struct Node
{
CParentis* content;
std::vector<Node*> children;
};
请注意,没有提及CPrimus
等。实际上,这个结构可以包含从CParentis
派生的任何内容,包括尚未编写类的实例。
您也可以使用std::whatever_smart_pointer_you_like<...>
而不是裸指针,任何容器都是方便的而不是矢量。
如果您可以修改CParentis
,则可以为其配备std::vector<CParentis*>
并取消Node
。
答案 2 :(得分:0)
你需要在树中存储CParentis的指针(或更好的智能指针)(当然很明显)。
现在,关于树的实现。首先,检查这个可能的副本:What's a good and stable C++ tree implementation?。
然后,这里有一个类似STL的树实现:http://tree.phi-sci.com/