Reputation: 1173
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
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
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