class AbstractNode { vector<unique_ptr<AbstractNode>> children; public: AbstractNode(arguments...); // other stuff... }; class Tree { unique_ptr<AbstractNode> baseNode; // other stuff... } unique_ptr<AbstractNode> constructNode(AbstractNodeTypes type);
abstractNode有各种子类,它们将包含在树中.子类为该类中的某些虚函数提供了不同的实现.
我希望能够通过创建一组具有相同类类型的新节点来复制我的树,这些类型是原始树中节点的不同副本.
这是问题所在:
如果我为深度复制子节点的AbstractNode类编写自己的复制构造函数,我将不得不为AbstractNode的所有子类编写复制构造函数,这看起来很烦人,因为唯一不能正确复制的是子指针.在这里使用复制构造函数也很烦人,因为我需要在调用之前将子项转换为正确的类型,我想.
有没有什么方法可以让编译器让我使用默认的复制构造函数来设置除孩子之外的所有东西.它可以将那些作为空指针或其他东西?然后我可以编写一个更简单的函数,只是递归地添加子项来复制树.
如果这是不可能的,那么任何人都知道这个问题是否有任何非丑陋的解决方案?
解决方法
class AbstractNode { std::vector<std::unique_ptr<AbstractNode>> children; public: AbstractNode() = default; virtual ~AbstractNode() = default; AbstractNode(AbstractNode const& an) { children.reserve(an.children.size()); for (auto const& child : an.children) children.push_back(child->clone()); } AbstractNode& operator=(AbstractNode const& an) { if (this != &an) { children.clear(); children.reserve(an.children.size()); for (auto const& child : an.children) children.push_back(child->clone()); } return *this; } AbstractNode(AbstractNode&&) = default; AbstractNode& operator=(AbstractNode&&) = default; // other stuff... virtual std::unique_ptr<AbstractNode> clone() const = 0; };
现在可以实现ConcreteNode.它必须具有有效的复制构造函数,可以根据ConcreteNode添加到混合的成员数据进行默认.它必须实现clone(),但该实现是微不足道的:
class ConcreteNode : public AbstractNode { public: ConcreteNode() = default; virtual ~ConcreteNode() = default; ConcreteNode(ConcreteNode const&) = default; ConcreteNode& operator=(ConcreteNode const&) = default; ConcreteNode(ConcreteNode&&) = default; ConcreteNode& operator=(ConcreteNode&&) = default; // other stuff... virtual std::unique_ptr<AbstractNode> clone() const override { return std::unique_ptr<AbstractNode>(new ConcreteNode(*this)); } };
我建议让clone返回一个unique_ptr而不是一个原始指针,以确保在没有所有者的情况下不会暴露出新指针.
为了完整起见,我还展示了其他特殊成员的样子.
起初我以为C 14的make_unique在这里使用会很好.它可以在这里使用.但我个人认为,在这个特殊的例子中,它确实没有发挥其重要作用. Fwiw,这就是它的样子:
virtual std::unique_ptr<AbstractNode> clone() const override { return std::make_unique<ConcreteNode>(*this); }
使用make_unique,你必须首先构造一个unique_ptr< ConcreteNode>,然后依赖于从它到unique_ptr< AbstractNode>的隐式转换.这是正确的,一旦内联完全启用,额外的舞蹈可能会被优化掉.但是,当你真正需要的是unique_ptr< AbstractNode>时,使用make_unique似乎是一种不必要的混淆.使用new’d ConcreteNode *构造.