Search code examples
c++c++14deep-copy

How to clone an object without copy constructor


According to CppCoreGuideline, I should disable the copy constructor of a base class and propose a clone method: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rc-copy-virtual

For example:

class B {
   public:
     explicit B() = default;
     B(B&&) = default; // Move constructor
     B& operator=(B&&) = default; // Move assignment operator
     B(const B&) = delete; // Copy constructor
     B& operator=(const B&) = delete; // Copy assignment
     virtual ~B() = default;

     virtual unique_ptr<B> clone()
     {
        return unique_ptr<B>{new B{*this}}; // how do this without copy constructor ?
     }
    private:
     int c;
     int d;
};

class D : public B {
    public:
     explicit D() = default;
     D(D&&) = default; // Move constructor
     D& operator=(D&&) = default; // Move assignment operator
     D(const B&) = delete; // Copy constructor
     D& operator=(const D&) = delete; // Copy assignment
     virtual ~D() = default;

     virtual unique_ptr<B> clone() override
     {
          //  how can I copy all private data member of base class ???
     }
};

but how can I copy all private data member in clone method? Obviously I'll use the CRTP pattern : C++: Deep copying a Base class pointer


Solution

  • I think the simplest way is to actually make the special members protected instead of deleted. This still prevents slicing, but makes it easier to implement clone(). Note that both the copy and move members need to be treated this way.

    class B {
    public:
        // if this is truly intended to be a polymorphic base class, it probably
        // doesn't make sense for the base to be able to clone itself.
        virtual unique_ptr<B> clone() = 0;
    
    protected:
        B(B const& ) = default;
        B& operator=(B const& ) = default;
    
    private:
        int c;
        int d;
    };
    

    Which also allows the derived classes to do this easily:

    class D : public B {
    public:
        D(D const& ) = default; // this is safe now
        D& operator=(D const& ) = default;
    
        unique_ptr<B> clone() override {
            return unique_ptr<D>(new D(*this));
        }
        // ...
    };