gpt4 book ai didi

c++ - 使用RTTI克隆唯一指针的 vector

转载 作者:行者123 更新时间:2023-12-02 10:00:44 24 4
gpt4 key购买 nike

我想使用RTTI克隆唯一指针的 vector 。
当前,有一个抽象基类Node以及派生类ElementTextNodeElement包含一个唯一的Node指针的 vector 。
我能够创建Element类型的对象并将其移到 vector 中。我希望能够克隆Element并将副本推送到 vector 中,但是我在Element的副本构造函数中苦苦挣扎。
这可能吗?如何使用RTTI克隆唯一的指针?有解决这个问题的更好方法吗?

#include <iostream>
#include <memory>
#include <string>
#include <vector>

struct Node {
virtual ~Node() = default;
virtual std::string toString() const = 0;
};

struct Element : Node {
Element() = default;
Element(const Element &element) {
// clone children
// for (const auto &child : element.children) children.push_back(std::make_unique</* get RTTI */>(child));
}
Element(Element &&) = default;
std::string toString() const override {
std::string str = "<Node>";
for (const auto &child : children) str += child->toString();
str += "</Node>";
return str;
}
std::vector<std::unique_ptr<Node>> children;
};

struct TextNode : Node {
std::string toString() const override { return "TextNode"; }
};

int main() {
Element root;
Element node;
node.children.push_back(std::make_unique<TextNode>());
// This copy doesn't work because I don't know how to implement the copy constructor
root.children.push_back(std::make_unique<Element>(node));
root.children.push_back(std::make_unique<Element>(std::move(node)));
root.children.push_back(std::make_unique<TextNode>());

std::cout << root.toString();
}
实际输出:

<Node><Node></Node><Node>TextNode</Node>TextNode</Node>


预期产量:

<Node><Node>TextNode</Node><Node>TextNode</Node>TextNode</Node>

最佳答案

您要求的内容无法直接使用RTTI完成,但可以通过手动检查类类型来间接完成。由于您只需要检查少量的类,因此可以这样进行:

#include <iostream>
#include <memory>
#include <string>
#include <vector>

struct Node {
virtual ~Node() = default;
virtual std::string toString() const = 0;
};

struct Element : Node {
Element() = default;

Element(const Element &element) {
// clone children
for (const auto &child : element.children) {
Node *n = child.get();
if (Element *e = dynamic_cast<Element*>(n)) {
children.push_back(std::make_unique<Element>(*e));
}
else if (TextNode *t = dynamic_cast<TextNode*>(n)) {
children.push_back(std::make_unique<TextNode>(*t));
}
}
}

Element(Element &&) = default;

std::string toString() const override {
std::string str = "<Node>";
for (const auto &child : children)
str += child->toString();
str += "</Node>";
return str;
}

std::vector<std::unique_ptr<Node>> children;
};

struct TextNode : Node {
std::string toString() const override { return "TextNode"; }
};

int main() {
Element root;
Element node;
node.children.push_back(std::make_unique<TextNode>());
root.children.push_back(std::make_unique<Element>(node));
root.children.push_back(std::make_unique<Element>(std::move(node)));
root.children.push_back(std::make_unique<TextNode>());

std::cout << root.toString();
}
但是,不用说,如果以后添加更多的后代类,这将变得乏味且容易出错。
更好的选择是在 clone()中添加一个虚拟的 Node方法,然后让 ElementTextNode(以及将来的后代)覆盖它来制作自己的副本,例如:
#include <iostream>
#include <memory>
#include <string>
#include <vector>

struct Node {
virtual ~Node() = default;
virtual std::string toString() const = 0;
virtual std::unique_ptr<Node> clone() const = 0;
};

struct Element : Node {
Element() = default;

Element(const Element &element) {
// clone children
for (const auto &child : element.children)
children.push_back(child->clone());
}

Element(Element &&) = default;

std::string toString() const override {
std::string str = "<Node>";
for (const auto &child : children)
str += child->toString();
str += "</Node>";
return str;
}

std::unique_ptr<Node> clone() const override {
return std::make_unique<Element>(*this);
}

std::vector<std::unique_ptr<Node>> children;
};

struct TextNode : Node {
std::string toString() const override { return "TextNode"; }

std::unique_ptr<Node> clone() const override {
return std::make_unique<TextNode>(*this);
}
};

int main() {
Element root;
Element node;
node.children.push_back(std::make_unique<TextNode>());
root.children.push_back(std::make_unique<Element>(node));
root.children.push_back(std::make_unique<Element>(std::move(node)));
root.children.push_back(std::make_unique<TextNode>());

std::cout << root.toString();
}

关于c++ - 使用RTTI克隆唯一指针的 vector ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62686665/

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