Search code examples
c++pointerspolymorphismclone

Cloning Pointers C++


This question is regarding copying and pointer polymorphism. Consider the code below. We have two classes: Base and Derived, which are just regular objects. Then we've got class Foo, which has a pointer to Base as its only member.

The typical usage of Foo is described in the main function. The input to Foo::SetMemberX may or may not be a temporary object.

The problem is that I want Foo::SetMember to create a proper copy of the passed object, and assign its address as a Base* to Foo::mMember.

I've managed to come up with 4 possible solution, none of which seem very elegant to me. The first three are shown in the code below in Foo::SetMember1, Foo::SetMember2, and Foo::SetMember3. The 4th option is to leave the memory allocation to the user (ex. foo.SetMember(new Derived())), which is not very desirable for obvious memory safety issues. Foo should be responsible for memory management, not the user.

#include <iostream>

template <typename tBase, typename tPointer>
void ClonePointer(tBase*& destination, const tPointer* pointer)
{
    destination = static_cast<tBase*>(new tPointer(*pointer));
}

// Base can be a virtual class
class Base
{
public:

    virtual void Function()
    {
        std::cout << "Base::Function()" << std::endl;
    }

    virtual Base* Clone() const = 0;
};

class Derived : public Base
{
public:

    virtual void Function()
    {
        std::cout << "Derived::Function()" << std::endl;
    }

    virtual Base* Clone() const
    {
        return new Derived(*this);
    }
};

class Foo
{
public:

    Foo() : mMember(NULL) { }

    ~Foo()
    {
        if (mMember != NULL)
        {
            delete mMember;
            mMember = NULL;
        }
    }

    template <typename T>
    void SetMember1(const T& t)
    {
        if (mMember != NULL)
        {
            delete mMember;
            mMember = NULL;
        }

        ClonePointer(mMember, &t);
    }

    void SetMember2(const Base& b)
    {
        mMember = b.Clone();
    }

    template <typename T>
    void SetMember3(const T& t)
    {
        if (mMember != NULL)
        {
            delete mMember;
            mMember = NULL;
        }

        mMember = new T(t);
    }

    Base& GetMember()
    {
        return *mMember;
    }

private:

    Base* mMember;
};

int main(int argc, char** argv)
{
    {
        Foo f1;
        Foo f2;
        Foo f3;

        // The input may or may not be a tempoary/RValue reference

        f1.SetMember1(Derived());
        f2.SetMember2(Derived());
        f3.SetMember3(Derived());

        f1.GetMember().Function();
        f2.GetMember().Function();
        f3.GetMember().Function();
    }

    // Output:
    // Derived::Function();
    // Derived::Function();
    // Derived::Function();

    system("pause"); // for quick testing
}

The problem with the first method (Foo::SetMember1) is that I have a random, free, template function, and a template accessore (see the problem with the third method below).

The problem with the second method (Foo::SetMember2) is that every derived class must implement its own Clone function. This is too much boilerplate code for the class user, as there will be a lot of classes deriving from Base. If I could somehow automate this, or create a base Cloneable class (without each Base-derived class having to explicitly calling it) with an implemented template Clone function, this would be the ideal solution.

The problem with the third method (Foo::SetMember3) is that I'd need a template accessor for Foo. This may not always be possible, especially because of how virtual template methods are not allowed in non-template classes (Foo cannot be a template itself), which is a functionality that might be required.

My questions are:

  1. Are these the only options I have?

  2. Is there a better, more elegant solution to this problem that I'm missing?

  3. Is there any way to create a base Cloneable class and derive Base from it, and have cloning automagically happen for DerivedType::Clone()?


Solution

  • For 2nd method, you can use CRTP and you won't need to write clone method in every derived class:

    struct Base {
      virtual ~Base() {}
      virtual Base *clone() const = 0;
    };
    
    template <typename Derived>
    struct CloneableBase : public Base {
      virtual Base *clone() const {
        return new Derived(static_cast<Derived const&>(*this));
      }
    };
    
    struct Derived: CloneableBase<Derived> {};