1

I am learning prototype design pattern and implementing a demo,I add deep copy constructors and clone functions to these classes,but I'm not sure if I implemented them correctly. I did the dynamic_cast conversion in otherNode, It‘s a little weird. Any suggestions?

class base {
public:
    explicit base() {}
    virtual ~base() = default;
    virtual base* clone() const = 0;
};

class ttNode : public base {
public:
    explicit ttNode() : base() {}
    ~ttNode() = default;
};

class SonNode : public ttNode {
public:
    SonNode() : ttNode() {}
    ~SonNode() = default;

    base* clone() const override {
        return new SonNode(*this);
    }
private:
    int c_{0};
    int a_{0};
};

class FatherNode : public ttNode {
public:
    FatherNode() : ttNode() {}
    ~FatherNode() = default;

    FatherNode(const FatherNode& node) : ttNode(node) {
        for (const auto &son : node.sons_) {
            sons_.emplace_back(new SonNode(*son));
        }
    }
    base* clone() const override {
        return new FatherNode(*this);
    }

private:
    std::vector<SonNode*> sons_;
};

class otherNode : public base {
public:
    otherNode() : base() {}
    ~otherNode() = default;
    base* clone() const override { return new otherNode(*this); }
    otherNode(const otherNode& node) : base(node) {
        ttt = dynamic_cast<ttNode*>(node.ttt->clone());
    }
private:
    ttNode* ttt;
};


TEST_F(tt, base1) {
    base *o = new otherNode();
    base *f = new FatherNode();
    base *o1 = o->clone();
    base *f1 = f->clone();
    delete o1;
    delete f1;
}

I can't use ttt = new ttNode(*node.ttt); because ttNode is abstract class.

bbbg
  • 11
  • 1
  • 1
    I don't understand the purpose of `ttNode`. It adds nothing, and if you remove it and use `base` instead then that `dynamic_cast` disappears. – john Apr 10 '23 at 08:31
  • Why using return type `base*` for overriding `clone`? You can override `clone` with derived type(e.g. `FatherNode*`) as return type. So, change so (and add such `clone` override to `ttNode`), then no `dynamic_cast` will be needed. – fana Apr 10 '23 at 08:47

1 Answers1

0

Your extensive use of raw pointers has made the code hard to maintain. And current snippet contains lots of memory leaks. Aside from the problem with raw pointers, the cannonical question can be answered in terms of covariant return types and/or CRTP. since C++20, CRTP can be implied using deduced this argument:

class base {
public:
    explicit base() {}
    virtual ~base() = default;
    auto static_clone(this const auto &self) { return std::make_unique<std::remove_cvref_t<decltype(self)>(self);};
};

The static_clone will eventually create correct type of unique pointer for each derived type. Combination of CRTP with covariant return type is what I have not tried yet; it seems to be complex, particularly if we want to try safty using smart pointers. But now you have two different routes to follow: covariant return and/or CRTP.

Red.Wave
  • 2,790
  • 11
  • 17