使用RTTI克隆唯一指针的向量

托马斯·萨布利克

我想使用RTTI克隆唯一指针的向量。

当前,有一个抽象基类,Node派生类ElementTextNodeElement包含向量的唯一Node指针。

我能够创建一个类型的对象Element并将其移动到向量中。我希望能够克隆anElement并将副本推送到向量中,但是我在与的copy构造函数作斗争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();
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章