Вызов реализации клона базового класса - PullRequest
0 голосов
/ 15 мая 2018

Пытается реализовать шаблон клонирования, но застрял в порядке вызова функции:

У меня есть класс Base с вектором полиморфных классов (Script).

В базовом классе реализована функция клона, которая, по сути, делает копию себя со всеми своими членами (вектор mScripts).

Производный класс также реализует свою собственную версию функции клонирования и заботится о клонировании своих членов. Который является целым числом в данный момент.

Вопрос: Как мне вызвать функцию клона Base class 'в функции Derived class', поэтому каждый класс заботится о клонировании свои члены?

Как уродливый обходной путь, сейчас функция клонирования всех моих производных классов вручную выполняет векторное клонирование 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;

};

Ответы [ 2 ]

0 голосов
/ 15 мая 2018

Например, определите дополнительный конструктор, который принимает 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;
    }
};
0 голосов
/ 15 мая 2018

Реализуйте конструктор копирования правильно, тогда каждая функция клонирования будет просто 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;
};
...