Home > Enterprise >  (C ) How to write a clone method for a class which has a unique pointer as a data member?
(C ) How to write a clone method for a class which has a unique pointer as a data member?

Time:04-16

I have the following set up:

class Base {
private:
// data members
public:
// methods
// pure virtual methods
virtual Base* clone() const =0;
}

class Derived : public Base{
private:
// more data members
public:
// more methods
// pure virtual methods overridden
Derived* clone() const override{
return new Derived(*this);
}

I now want to introduce a new derived class which, in the context of a decorator pattern, has a unique pointer to a Base class object as a data member. My question is then how to properly implement the clone() method because the "standard" implementation leads to a compile time error as the unique pointer can't be copied:

class DecoratedDerived : public Base{
private:
unique_ptr<Base> ptr;
// more data members
public:
// more methods
// pure virtual methods overridden
DecoratedDerived* clone() const override{
return new DecoratedDerived(*this); // compiler error
}

One solution would be to just construct a new DecoratedDerived class object in the clone method (by explicitly deep copying all the members associated to the current object) and then passing a pointer to this. However this is quite time consuming if the class has a lot of other members.

I should also say that I am only using a unique pointer because this seems the standard smart pointer to use in modern C . In particular before I used C 11 I had just designed my own smart pointer which took care of all the memory management etc. so that for that type of smart pointer there would be no issue with the clone method in the decorated class.

Thanks in advance for your help!

CodePudding user response:

Here is possible implementation, when new DecoratedDerived is constructed member item is cloned too:

class Base {
   public:
    virtual std::unique_ptr<Base> clone() const = 0;
};

class Empty : public Base {
   public:
    std::unique_ptr<Base> clone() const override {
        return std::make_unique<Empty>();
    }
};

class DecoratedDerived : public Base {
   private:
    std::unique_ptr<Base> ptr;

   public:
    DecoratedDerived() : ptr{std::make_unique<Empty>()} {}

    DecoratedDerived(std::unique_ptr<Base> wrap) : ptr{std::move(wrap)} {}

    std::unique_ptr<Base> clone() const override {
        return std::make_unique<DecoratedDerived>(ptr->clone());
    }
};

https://godbolt.org/z/sG3zTehb1

Empty class is a nice way to avoid checking for nullptr.

Note also since you are using unique_ptr I've introduce them in other places when it seems logical.

CodePudding user response:

Simply add a copy constructor to DecoratedDerived that clone()'s the data member, eg:

class DecoratedDerived : public Base {
private:
    unique_ptr<Base> ptr;
    // ...
public:
    DecoratedDerived(const DecoratedDerived &src)
        : Base(src), ptr(src.ptr ? src.ptr->clone() : nullptr)
    {
    }

    // ...

    DecoratedDerived* clone() const override{
        return new DecoratedDerived(*this);
    }
};

Online Demo

  • Related