Avi
Avi

Reputation: 1173

Calling base class clone implementation

Trying to implement clone pattern, but stuck with the function invoking order:

I have a Base class with a vector of polymorphic classes (Script).

Base class's implements a clone function, which essentially makes a copy of itself with all its members (mScripts vector).

Derived class's also implements its own version of clone function, and take care of its members cloning. Which is only an integer at this moment.

The question: How should I invoke Base class' clone function, in Derived class' clone function, so each class takes care of the cloning of its own members?

As an ugly workaround, right now, all my Derived classes' clone function manually do the mScripts vector cloning basically repeating the same code.

class Base
{
public:

    virtual std::unqique_ptr<Base> clone()
    {
        std::unique_ptr<Base> clonedInstance = std::make_unique<Base>();

        //clone the underlying vector
        for(int i = 0; i < mScripts.size(); ++i)
        {
            clonedInstance->mScripts.push_back(std::move(mScripts[i]->clone()));
        }

        return std::move(clonedInstance);
    }

    std::vector<std::unique_ptr<ScriptBase>>    mScripts;   //polymorphic array
};



class Derived : public Base
{
public:

    Derived(const int x) : Base(), mX(x)
    {
    }

    std::unqique_ptr<Base> clone()
    {
        //calling base::clone() here?

        return std::unique_ptr<Base> clonedInstance = std::make_unique<Derived>(mX);
    }

private:

    int mX;

};

Upvotes: 0

Views: 111

Answers (2)

bipll
bipll

Reputation: 11940

For instance, define an additional constructor that accepts a Base as argument. Make it private if you don't want to expose it:

struct Base {
     Base(Base &&) = default;
};

class Derived: public Base {
    Derived(Base &&b, int x): Base(std::move(b)), mX(x) {}
public:
    std::unique_ptr<Base> clone() const {
        auto retBase{Base::clone()};
        return std::make_unique<Derived>(std::move(*retBase), mX);
    }
};

(your Base is not trivially copyable anyway.)

Another way is to add templated cloning, when all the Base cloning is done inside a CRTP-like templated function with possible further tweaks to the returned value:

class Base {
protected:
    template<typename Concrete> std::unique_ptr<Base> recreate() const {
         std::unique_ptr<Base> retVal{std::make_unique<Concrete>()};
         // ???????
         return retVal;
    };
public:
    virtual std::unique_ptr<Base> clone() const { return recreate<Base>(); }
};

struct Derived: public Base {
    std::unique_ptr<Base> clone() const {
        auto retVal{recreate<Derived>()};
        retVal->mX = mX;
        return retVal;
    }
};

Upvotes: 1

Jarod42
Jarod42

Reputation: 217293

Implement copy constructor correctly, then each clone function is simply return std::make_unique<Derived>(*this);

class Base
{
public:
    Base() = default;
    Base(const Base& rhs) // default is not fine here
    {
        for (const auto& script : rhs.mScripts)
        {
            mScripts.push_back(script->clone());
        }
    }
    virtual ~Base() = default;

    virtual std::unique_ptr<Base> clone() const
    {
        return std::make_unique<Base>(*this);
    }

    std::vector<std::unique_ptr<ScriptBase>> mScripts;   //polymorphic array
};

class Derived : public Base
{
public:
    Derived(int x) : Base(), mX(x) {}
    Derived(const Derived&) = default; // Default is fine here

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

private:
    int mX;
};

Upvotes: 2

Related Questions