【发布时间】:2019-01-30 21:08:53
【问题描述】:
我遇到了上述问题。我想构建一棵带有关联节点的树。由于所有树的行为相同但类型不同,因此本着继承的精神,我希望能够使用基类定义的相同树构造例程来构造具有不同类型的树。我想知道最适合我的情况的做法。
struct Tree
{
struct Node { std::list<std::shared_ptr<Node>> children_; };
Tree()
{
root_ = CreateNode();
// carry on adding nodes to their parents...
}
virtual std::shared_ptr<Node> CreateNode() { return std::shared_ptr<Node>(new Node()); }
std::shared_ptr<Node> root_;
};
struct TreeDerived : public Tree
{
struct NodeDerived : public Tree::Node {};
TreeDerived() : Tree() {}
virtual std::shared_ptr<Node> CreateNode() { return std::shared_ptr<NodeDerived>(new NodeDerived()); }
};
问题是我不能调用派生函数,直到基被构造(显然),并且使用CreateNode 方法的基实现,该方法总是用基节点实现构造树。这意味着我可以在不延迟树木数量的情况下建造树木。显而易见的解决方案是将树模板化以采用不同的节点类型,使用特征强制执行节点类型?但是,这也意味着所有方法的定义都必须在标题中?这门课很丰富,所以我想尽可能避免这种情况,所以我考虑传递一个 lambda 来为我做这件事。
struct Tree
{
struct Node { std::list<std::shared_ptr<Node>> children_; };
Tree(std::function<std::shared_ptr<Node>()> customNodeConstructor)
{
root_ = customNodeConstructor();
// carry on adding nodes to their parents... using the customNodeConstructor to create the nodes.
}
std::shared_ptr<Node> root_;
};
struct TreeDerived : public Tree
{
struct NodeDerived : public Tree::Node {};
TreeDerived(std::function<std::shared_ptr<Node>()> customNodeConstructor) : Tree(customNodeConstructor) {}
};
这允许我派生并传递与派生树相关的customNodeConstructor。由于返回的shared_ptr 对象必须从Tree::Node 派生,因此部分强制执行类型安全,尽管对派生节点类型没有强制执行。
即TreeDerived 实例化,可能应该使用TreeDerived::NodeDerived,但仅强制使用Tree::Node 或派生类型,但不一定使用TreeDerived::NodeDerived。
然后可以这样使用...
Tree tree([]() { return std::shared_ptr<Tree::Node>(); });
TreeDerived treeDerived([]() { return std::shared_ptr<TreeDerived::NodeDerived>(); });
这是一种好的做法,还是我应该在不模板化 Tree 对象的情况下做更多/其他事情?
非常感谢。
【问题讨论】:
-
你考虑过模板吗?
template<class T> struct Tree;? -
@YSC 谢谢,是的,模板是解决这个问题的明显方法,但如果可以的话,我想避免这种情况,因为我想避免在标题中放入相当多的代码。
-
您不必必须,只要您明确地使用模板将使用的所有类型专门化您的模板。见stackoverflow.com/a/495056/5470596
-
为什么不简单地拥有不同事物的不同树?
-
@YSC 啊,好吧,不知道可以这样做。我一直认为模板的实现需要在标题中完成。不错!
标签: c++ constructor virtual c++17