Search code examples
c++copypolymorphismcopy-constructorfactory-pattern

Polymorphic object copying


The following pattern is old and well known.

class A 
{
public:
    virtual A* clone() const 
    {
        return new A(*this);
    }

private:
   int x = 666;
};

class B : public A
{
public:    
    virtual B* clone() const override 
    {
        return new B(*this);
    }

private:
    int y = 777;
};

Now I would like to copy objects in a polymorphic way from other objects. I want to be able to:

  1. Create objects of type A by copying from objects of type B
  2. Create objects of type A by copying from objects of type A
  3. Create objects of type B by copying from objects of type A
  4. Create objects of type B by copying from objects of type B

I am aware that the case 1 includes slicing but this is desired. Also I am aware that case 3 doesn't copy y, this is desired too (I want to use the default init value).

All 4 cases should be done polymorphic... knowing the destination type but without knowing the actual source object type.

How can the above pattern be extended (or how would an alternative pattern look like) that is able to do this without using RTTI?


Solution

  • From what I understand, you may do

    class B; // Forward declaration needed for A::CreateB
    
    class A 
    {
    public:
        A() = default;
        A(const A&) = default; // A(b) will do slicing as expected.
        virtual ~A() = default;
    
        virtual A* clone() const { return new A(*this); }
        virtual B CreateB() const; // Implementation should go after B definition.
    
    private:
       int x = 666;
    };
    
    class B : public A
    {
    public:
        B() = default; // previous constructor
        B(const A&a) : A(a) {} // Create B from A  (non polymorphic)
        B(const B&) = default; // Copy constructor (non polymorphic)
    
        virtual B* clone() const override { return new B(*this); }
        virtual B CreateB() const { return B(*this); }
    
    private:
        int y = 777;
    };
    
    B A::CreateB() const { return B(*this); }
    
    • Create objects of type A by copying from objects of type B
    • Create objects of type A by copying from objects of type A

    Those two doesn't require polymorphism, A(constA&) does the job

    • Create objects of type B by copying from objects of type A
    • Create objects of type B by copying from objects of type B

    Those two are handled by virtual CreateB which forward to the constructor of B (similar to visitor pattern).