gpt4 book ai didi

c++ - std::unique_ptr、默认复制构造函数和抽象类

转载 作者:可可西里 更新时间:2023-11-01 18:15:55 25 4
gpt4 key购买 nike

我有一个类表示一个使用唯一指针的树对象,一些构成树的节点,以及一个基于一些参数构造指向抽象节点类的指针的函数(它指向子类,因为抽象节点是抽象的)

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 的所有子类编写复制构造函数,这看起来很烦人,因为唯一不能正确复制的是子指针。在这里使用复制构造函数也会很烦人,因为我认为在调用它们之前我需要将子对象强制转换为正确的类型。

有什么方法可以让编译器让我使用默认的复制构造函数来设置除子项之外的所有内容。它可以将它们保留为空指针之类的吗?然后我可以编写一个更简单的函数,它只是递归地添加 child 来复制一棵树。

如果那是不可能的,有没有人知道这个问题的任何非丑陋的解决方案?

最佳答案

解决这个问题的典型方法是有一个虚拟clone功能类似于 Kerrek SB 在他的回答中描述的内容。但是我不会费心写你自己的 value_ptr类(class)。重用 std::unique_ptr 更简单如您的问题所示。在 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> 的隐式转换.这是正确的,一旦完全启用内联,额外的舞蹈可能就会被优化掉。但是使用make_unique当您真正明确需要的是 unique_ptr<AbstractNode> 时,这里似乎是不必要的混淆用新的 ConcreteNode* build .

关于c++ - std::unique_ptr、默认复制构造函数和抽象类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24221607/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com