调用基础 class 克隆实现

Calling base class clone implementation

正在尝试实现克隆模式,但坚持函数调用顺序:

我有一个 Base class 带有多态向量 classes(脚本)。

Base class's 实现了一个克隆函数,它本质上是复制它自己及其所有成员(mScripts 向量)。

Derived class's 也实现了自己的克隆函数版本,并负责其成员的克隆。目前只是一个整数。

问题:我应该如何调用Base class'克隆函数,在Derived class' 克隆函数,所以每个 class 都负责克隆自己的成员?

作为一个丑陋的解决方法,现在,我所有的 Derived classes 克隆函数手动执行 mScripts 矢量克隆,基本上重复相同的代码。

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;

};

正确实现拷贝构造函数,那么每个克隆函数就是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;
};

例如,定义一个额外的构造函数,它接受一个 Base 作为参数。不想暴露就设为private:

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);
    }
};

(你的 Base 无论如何都不可复制。)

另一种方法是添加模板克隆,当所有 Base 克隆都在类似 CRTP 的模板函数内完成时,可能会进一步调整返回值:

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;
    }
};