Reputation: 3523
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
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
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
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:
ClonablePBase
class with a virtual clone
method and a virtual destructorClonableP
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.AnyP
class that holds std::auto_ptr<ClonablePBase>
. It copies itself by calling the virtual clone method.Upvotes: 0