Re: Automatically create a clone() function for derived classes
Noah Roberts wrote:
blargg wrote:
[...]
Odd-ball approach that comes to mind, if compile-time checking is
insisted on:
class Clonable {
protected:
template<class T>
Clonable( T const* t )
{
// ensure that T implements covariant clone
if ( false )
t = t->clone();
Calling virtual function from within constructor == very bad. Besides
that it looks like a rather interesting solution.
Controlled by an if statement whose condition is never true == perfectly
OK. The purpose is to ensure that T's clone function returns a T* (or
something derived from it). This way, if T forgets to define clone, the
base class version would be found and its return type wouldn't be
implicitly convertible to T*.
I think you could improve it through something similar to boost::any:
class Clonable {
protected:
template < typename T >
Clonable( T const* t) : pimpl(new impl<T>(t))
{}
Clonable * clone() const { return pimpl->clone(); }
private:
struct impl_base
{
virtual Clonable* clone() const = 0;
};
template < typename T >
struct impl : impl_base
{
impl(T const* t) : var(t) {}
Clonable * clone() const { return new T(var); }
T const* var;
};
scoped_ptr<impl_base> pimpl;
};
Leave your virtual inheritance and turn Base::clone into:
Base * Base::clone() const { return static_cast<Base*>(Clonable::clone()); }
Wouldn't even need to be virtual as the polymorphism is taken care of by
Clonable's pimpl.
The virtual inheritance is necessary to force the most-derived class to
call the Clonable constructor with the 'this' pointer, to indirectly
pass its type. BTW, you don't need any type of embedded object at all,
just a function pointer:
class Clonable {
template<class T>
static Clonable* clone_t( Clonable const* c ) {
return new T( static_cast<T const*> (c) );
}
Clonable* (*clone_)( Clonable* );
protected:
template<class T>
Clonable( T* ) : clone_( &clone_t<T> ) { }
public:
Clonable* clone() const { return clone_( this ); }
};
class Base : public virtual Clonable {
public:
Base() : Clonable( this ) { }
Base* clone() const {
return static_cast<Base*> (Clonable::clone());
}
};
class Derived : public Base {
public:
Derived() : Clonable( this ) { }
// if you forget this, user is merely inconvenienced, rather
// than given Base slice of the object
Derived* clone() const {
return static_cast<Derived*> (Clonable::clone());
}
};
This is untested but I'm pretty confident it, or something like it,
would work. The only thing lost is the ability to construct Derived
pointers without casts even when you know the Derived type. Some sort
of policy based programming might do the trick there.
Or just forwarding functions as you mentioned. Of course I think the cost
of ensuring correct clone() implementation greatly outweights the benefit,
as compared to using external tests to ensure each class implements a
clone in the straight-forward way:
Foo* clone() const { return new Foo( *this ); }