Automatically create a clone() function for derived classes

J

Juha Nieminen

I'm sure this is a frequently asked question, but...

Suppose that I have a hierarchy of objects which are typically
allocated dynamically and handled with some smart pointer or whatever.
However, I want to be able to create copies of those objects, while
having only a pointer-to-base-class. The solution is to write a clone()
member function like this:

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

// other stuff here
};

The problem is that this clone() function must be replicated in all
the derived classes as well, and their implementation is always the
same, except for the type which is being allocated. For example:

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

It's not only tedious to have to write this line in each of the
derived classes, but it's also error-prone: If you ever forget to add
that line to some derived class, no compiler error will happen, and the
program will even run, but when cloning a derived object using a base
type pointer, you get a crippled copy, so the whole thing malfunctions,
and it might malfunction in a very non-obvious way which is hard to
track and debug.

Isn't there any way of automating this process? (And without making
the base class a template class, which would be rather tedious if the
base class is large, especially since we don't have export templates in
practice.)
 
S

Sana

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

    // other stuff here

};

  The problem is that this clone() function must be replicated in all
the derived classes as well, and their implementation is always the
same, except for the type which is being allocated. For example:

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

};

  It's not only tedious to have to write this line in each of the
derived classes, but it's also error-prone: If you ever forget to add
that line to some derived class, no compiler error will happen, and the
program will even run, but when cloning a derived object using a base
type pointer, you get a crippled copy, so the whole thing malfunctions,
and it might malfunction in a very non-obvious way which is hard to
track and debug.

Make the Base::clone() method pure and don't provide a body. this way,
if the derived class doesn't implement the clone() method, the linker
will complain.

virtual Base* clone() const = 0;
 
T

Thomas J. Gritzan

Juha said:
I'm sure this is a frequently asked question, but...

It is (but it's not in the FAQ)!
Suppose that I have a hierarchy of objects which are typically
allocated dynamically and handled with some smart pointer or whatever.
However, I want to be able to create copies of those objects, while
having only a pointer-to-base-class. The solution is to write a clone()
member function like this:

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

// other stuff here
};

The problem is that this clone() function must be replicated in all
the derived classes as well, and their implementation is always the
same, except for the type which is being allocated. For example:
[...]

1) You can use CRTP to avoid writing all the code again and again.
2) You can try some programming by contract to check if someone forgot
to implement its clone().

Both is described in this posting (the complete thread might be of
interest, too):
http://groups.google.de/group/comp.lang.c++.moderated/msg/993079dca61f3a20?hl=de
 
N

Noah Roberts

blargg said:
class Base
{
public:
virtual Base* clone() const { return new Base(*this); }

// other stuff here
};

The problem is that this clone() function must be replicated in all
the derived classes as well, and their implementation is always the
same, except for the type which is being allocated. For example:

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

It's not only tedious to have to write this line in each of the
derived classes, but it's also error-prone: If you ever forget to add
that line to some derived class, no compiler error will happen, and the
program will even run, but when cloning a derived object using a base
type pointer, you get a crippled copy, so the whole thing malfunctions,
and it might malfunction in a very non-obvious way which is hard to
track and debug.

Isn't there any way of automating this process?
[...]

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. 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.

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.
 
T

tharinda.gl

but it's also error-prone: If you ever forget to add
that line to some derived class, no compiler error will happen, and the
program will even run, but when cloning a derived object using a base
type pointer, you get a crippled copy, so the whole thing malfunctions,
and it might malfunction in a very non-obvious way which is hard to
track and debug.

Hi,

I'm not a c++ expert but can't we tackle this problem by having co-
variant virtual functions at the derived classes ?

so it would be like

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

// other stuff here

};

AND

class Derived: public Base
{
public:
virtual Derived* clone() const { return new Derived(*this); } //
return type is different

};

when you clone an object of the type "Derived" and try to assign it to
a pointer to the type "Derived" it will fail at compile time if there
is no such co-variant implementation in the derived type.

Of course you can use macros to do it like this

#define DECLARE_CLONE(class_name) \
virtual class_name* Clone();

#define IMPLEMENT_CLONE(class_name) \
class_name* class_name::Clone() \
{ return new class_name(*this); }
 
R

REH

when you clone an object of the type "Derived" and try to assign it to
a pointer to the type "Derived" it will fail at compile time if there
is no such co-variant implementation in the derived type.

If that were the case, he could simple use a copy constructor. The
problem is he only has a pointer to the base class, and doesn't know
the actual type. Thus, the need for a polymorphic member function to
do the work for him.

REH
 
T

tharinda.gl

But even with covariant overrides of clone(), if someone clones a Derived
object given just a Base*, a forgotten override of clone() in Derived
won't be caught.

that problem would be solved if you use a macro to declare and define
the class methods :)

Thanks!

Tharinda
 
T

tharinda.gl

How does defining such a macro prevent one from forgetting to invoke it?

I mean if somebody is strictly adhered to a rule so that the clone
function is implemented only by a macro like this

#define DECLARE_CLONE(class_name) \
virtual class_name* Clone();

#define IMPLEMENT_CLONE(class_name) \
class_name* class_name::Clone() \
{ return new class_name(*this); }

then there is no way you can accidentally change the return type of
the derived function.

Thanks!

Tharinda
 
T

tharinda.gl

blargg said:
I think you missed the main point; I'll recap since I'm not sure where
we diverge. The original poster wanted to use a virtual clone() in the
base class, but wanted a way to catch the error of forgetting to
override it in derived classes, even multiple levels deep (where making
the base function pure wouldn't help). He wanted a compile-time error,
but I've generalized that to reliably getting SOME kind of error.

You noted that with covariant return types, this error will be caught in
some cases at compile-time:

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

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

class Error : public Base {
public:
// forgot clone()
};

void user( Base* b, Derived* d, Error* e )
{
d = d->clone(); // OK
e = e->clone(); // error, since e.clone() returns a Base*

b = b->clone(); // OK, even if b points to an Error object
}

If an error object were only ever cloned via a Base*, the error would
never be reliably caught. Thus, using covariant returns isn't sufficient
to reliably catch the error of a forgotten clone() override. Using a
macro to automate the declaration/definition of derived clone() doesn't
do anything to prevent the derived class author from forgetting to
invoke it. My point about using a Base* in the quoted message wasn't
about the derived class author overriding clone() wrong; it was about
him not overriding it at all, and users cloning entirely through Base*.

Sorry for the verbosity.

blargg, Yes you are correct, my solution won't be a concrete method of
finding whether the developer has forgotten to implement the clone
method at the derived class. I assumed following things in my
solution.

1. If we don't have the definition of the Derived class then there is
no point of making sure the created object is really a object of the
derived type since we only have access to the base type. This may not
be true for all the cases.

2. If you want to do some kind of down-casting then you have to worry
about the actual data type at that point.

2. If you have the definition of the derived type then you can always
use a pointer to to that type in order to get the cloned object (so
that the compiler error would be generated if there is no such
overridden method).

3. You can make sure the return type always refers to the most derived
type by using some kind of a macro.

As I have mentioned earlier, I am not a c++ pro and still learning
this marvelous language. I really appreciate on the effort that you
people are putting in order improve our knowledge.

Thanks!

Tharinda
 
B

Bart van Ingen Schenau

blargg, Yes you are correct, my solution won't be a concrete method of
finding whether the developer has forgotten to implement the clone
method at the derived class. I assumed following things in my
solution.

1. If we don't have the definition of the Derived class then there is
no point of making sure the created object is really a object of the
derived type since we only have access to the base type. This may not
be true for all the cases.

In fact, it is extremely rare that this assumption would be true.
In general, if you have
T* orig;
T* p_new;
//...
p_new = orig->clone();
then most programmers will assume that
orig->do_something();
and
p_new->do_something();
will have exactly the same effect on their respective objects.

It does not matter that you don't know about the additional functions
that a derived class exposes. The expectation is that the virtual
functions that you call (indirecly) through the Base interface resolve
to the same functions.
Thanks!

Tharinda

Bart v Ingen Schenau
 
N

Noah Roberts

Noah said:
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;
};

Actually, thinking about it more I'm pretty confident that this
interface could be further extended so that the clone functionality
isn't even in the class you're using and you could use ANY inheritance
tree in this manner. This would be the optimal design in many cases.

You would simply implement this as a sort of smart pointer that does
deep-cloning on whatever object it points to. Should be relatively
straightforward to implement using the techniques in the above so I'm
not going to do so here.

What would be really nice is a policy based smart pointer that you could
add this functionality to as a policy. Might look into Loki to see if
it's there already.
 
J

James Kanze

I'm sure this is a frequently asked question, but...
Suppose that I have a hierarchy of objects which are typically
allocated dynamically and handled with some smart pointer or
whatever. However, I want to be able to create copies of
those objects, while having only a pointer-to-base-class. The
solution is to write a clone() member function like this:
class Base
{
public:
virtual Base* clone() const { return new Base(*this); }

// other stuff here
};
The problem is that this clone() function must be replicated
in all the derived classes as well, and their implementation
is always the same, except for the type which is being
allocated. For example:
class Derived: public Base
{
public:
virtual Base* clone() const { return new Derived(*this); }
};
It's not only tedious to have to write this line in each of
the derived classes, but it's also error-prone: If you ever
forget to add that line to some derived class, no compiler
error will happen, and the program will even run, but when
cloning a derived object using a base type pointer, you get a
crippled copy, so the whole thing malfunctions, and it might
malfunction in a very non-obvious way which is hard to track
and debug.
Isn't there any way of automating this process? (And without
making the base class a template class, which would be rather
tedious if the base class is large, especially since we don't
have export templates in practice.)

I would imagine some development tools would have a means of
automatically generating the function. Otherwise, blargg and
Noah Roberts have proposed an interesting solution, albeit with
some runtime overhead (an additional dynamic
allocation---probably not significant for the types of things
which usually get cloned). But is the extra code really a
problem? It's not that much. The "classical" solution settles
for a runtime check:

class Base
{
public:
Base* clone() const
{
Base* result = doClone() ;
assert( typeid( *result ) == typeid( *this ) ) ;
return result ;
}

private:
virtual Base* doClone() const = 0 ;
} ;

(Actually, the classical solution doesn't do anything special.
In practice, I've never found forgetting to implement the clone
function in a derived class to be a real problem. All the more
so in that hierarchies which support cloning rarely contain
classes which derive from a concrete type anyway, so making
clone() pure virtual in the base class suffices to ensure a
compiler error.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top