gator
gator

Reputation: 3523

Can a copy constructor be defined in the base class and still handle derived class circumstances?

I have a class structure like below:

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

class A : public P {
    public:
        std::auto_ptr<P> clone() const {
            return std::auto_ptr<P>(new A(*this));
        }
};

class B : public P {
    public:
        std::auto_ptr<P> clone() const {
            return std::auto_ptr<P>(new B(*this));
        }
};

class C : public P {
    public:
        std::auto_ptr<P> clone() const {
            return std::auto_ptr<P>(new C(*this));
        }
};

This is just the code for the copy constructors: classes A, B, C all have different code otherwise. There's a lot of code reduplication here, can it be simplified?

Upvotes: 0

Views: 119

Answers (3)

R Sahu
R Sahu

Reputation: 206697

Can a copy constructor be defined in the base class and still handle derived class circumstances?

In general, the short answer is "No".

It works fine if the compiler generated copy constructors are sufficient.

If a derived class is defined such that the compiler generated copy constructor is not adequate, there is no way to get around the need to define one in the derived class.

Upvotes: 0

Jarod42
Jarod42

Reputation: 217880

With CRTP, you might do:

template <typename Derived, typename Base>
struct Clonable : public Base
{
    std::auto_ptr<Base> clone() const {
        return std::auto_ptr<Base>(new Derived(static_cast<const Derived&>(*this)));
    }
};

class A : public Clonable<A, P> {}; 
class B : public Clonable<B, P> {}; 
class C : public Clonable<C, P> {}; 

And to benefit of real type for derived classes, I would modify code to:

class P {
public:
    std::auto_ptr<P> clone() const { return std::auto_ptr<P>(vclone()); }
private:
    virtual P* vclone() const = 0;
};

template <typename Derived, typename Base>
struct Clonable : public Base
{
    std::unique_ptr<Derived> clone() const {
        return std::unique_ptr<Derived>(static_cast<Derived*>(vclone()));
    }
private:
    // Cannot use covariant-type `Derived*` in CRTP as Derived is not complete yet
    Base* vclone() const {
        return new Derived(static_cast<const Derived&>(*this));
    }
};

class A : public Clonable<A, P> {}; 
class B : public Clonable<B, P> {}; 
class C : public Clonable<C, P> {}; 

So, following is valid:

A a;
std::auto_ptr<A> a_copy =  a.clone();

Upvotes: 1

Brian Bi
Brian Bi

Reputation: 119392

If you mean something like whether there's a way to give each derived class a clone method without having to explicitly write it out: the answer is no. This is one thing that would become possible if metaclasses were added to C++, but don't expect that to make it into the language for a while.

However, Boost.Any can copy objects without knowing their dynamic type and is implementable in C++03. If you wanted to, you could use a similar type erasure technique. In short, this would consist of:

  • A ClonablePBase class with a virtual clone method and a virtual destructor
  • A ClonableP class template that derives from ClonablePBase. An object of type ClonableP<T> (where T is derived from P) holds a T object and knows how to clone itself using T's copy constructor.
  • An AnyP class that holds std::auto_ptr<ClonablePBase>. It copies itself by calling the virtual clone method.

Upvotes: 0

Related Questions