Estou limitado ao C++17. Preciso fazer uma estrutura de árvore (não necessariamente binária) que possa ser profundamente copiada em 2 clones independentes. Atualmente, tenho uma Node
classe de interface onde há 2 implementações:
Uma
Operation
classe contém um enum representando a operação booleana a ser realizada em seusstd::vector<std::unique_ptr<Node>>
operandos. Esses constituem os ramos na árvore.Uma
Condition
classe contém os dados que serão comparados quando for dito para avaliar. Eles compõem as folhas na árvore.
Por fim, tenho uma Event
classe com a std::unique_ptr
que aponta para a raiz Node
desta árvore. Tanto Operation
an quanto Condition
podem ser a raiz da árvore.
Tenho seguido esta postagem do blog em relação à clonagem adequada de um std::unique_ptr
, mas não sei bem como manter a parte polimórfica dos construtores de cópia das classes Event
and Operation
. Ter esses construtores de cópia é uma parte inerente do meu problema?
#include <algorithm>
#include <memory>
#include <string>
#include <vector>
namespace tree
{
struct Node
{
// Virtual clone function to make a new std::unique_ptr
// with a copy of the contents of the old std::unique_ptr
// Both std::unique_ptrs will be independent of each other
virtual std::unique_ptr<Node> clone() const = 0;
std::string name;
};
enum class Boolean
{
And,
Or,
Xor
};
struct Operation : public Node
{
// Copy constructor (because copying a std::vector is non-trivial)
// that will allocate a new std::vector of the same size and clone
// new std::unique_ptrs from the other std::vector
Operation(const Operation &other) : op(other.op), nodes(other.nodes.size())
{
std::transform(other.nodes.cbegin(), other.nodes.cend(), nodes.begin(),
[](const auto &old) {
// This line has the compilation error because Node is abstract,
// but I need this for the polymorphism, correct?
return op ? std::make_unique<Node>(old->clone()) : nullptr;
});
}
// Clones this class
virtual std::unique_ptr<Node> clone() const override
{
return std::make_unique<Operation>(*this);
}
Boolean op;
// Can hold any number of other Operation or Condition objects
std::vector<std::unique_ptr<Node>> nodes;
};
struct Condition : public Node
{
// Clones this class
virtual std::unique_ptr<Node> clone() const override
{
return std::make_unique<Condition>(*this);
}
int datum;
};
struct Event
{
Event(std::string name) : name(name) {}
// This line has the same compilation error
Event(const Event &other) : name(other.name), root(std::make_unique<Node>(other.root->clone())) {}
std::string name;
std::unique_ptr<Node> root;
};
} // tree
Você já sabe como clonar um objeto polimórfico. Você só precisa usar a funcionalidade de clonagem corretamente em seus construtores de cópia. Você não deve usar
std::make_unique<Node>()
para copiar um clone, apenas use o clone como está, por exemplo:Como alternativa, você pode usar uma função auxiliar para tornar a clonagem um pouco mais limpa:
std::make_unique<Node>
precisaNode
ser completo, porque ele tem que procurar porNode
construtores s. MasNode
é abstrato e não pode ser construído por si só.A construção de movimento de um
std::unique_ptr<Node>
, por outro lado, apenas copia um ponteiro.Altere a linha para:
E o mesmo para a outra linha.
Demonstração ao vivo