[comp.lang.c++] Cloning derived classes

kc@rna.UUCP (Kaare Christian) (05/02/90)

I recently needed to make a copy (a clone) of a class object, given only a
base class pointer to the object.  C++ lets you do some things with a class,
knowing only its base type, but it doesn't provide an easy way to make
a copy.  My solution was to make a virtual member function that
returned the size of each of the derived classes, and then make an
operator= function (left arg, ref pointer to base, right arg, ref to
base) that did the work - it called the size fn of the right operand to
determine how much space was needed, allocated it, did a bitwise copy,
then did some housekeeping.

Shouldn't this be easier? Given a (base *) pointer to a derived object,
I think it should be easy to make a copy of the thing pointed at.

One way might be to add a clone facility, that would be used equivalently
to new, but that would duplicate an existing object.
	Base *p = ... ;
	Base *b;
	b = clone *p; // new takes a type, clone takes an object

Another method might be to have a typeof builtin, perhaps similar to the
following:
	Base *p = .... ;
	Base *b;
	b = new typeof(*p);	// allocates space
	*(typeof(*p) *)b = *(typeof(*p) *)p;	// ugly, but copies whole thing

Kaare Christian
kc@rna.rockefeller.edu

jbuck@carson.berkeley.edu (Joe Buck) (05/03/90)

In article <1019@rna.UUCP>, kc@rna.UUCP (Kaare Christian) writes:
> I recently needed to make a copy (a clone) of a class object, given only a
> base class pointer to the object.  C++ lets you do some things with a class,
> knowing only its base type, but it doesn't provide an easy way to make
> a copy.  My solution was to make a virtual member function that
> returned the size of each of the derived classes, and then make an
> operator= function (left arg, ref pointer to base, right arg, ref to
> base) that did the work - it called the size fn of the right operand to
> determine how much space was needed, allocated it, did a bitwise copy,
> then did some housekeeping.

You're working too hard.

All you really need to do is call the copy constructor from a virtual
function.  In the base class (I'll assume it's virtual) do

class BaseType {
	virtual BaseType* copy () = 0;
}

For EACH derived class you must redefine the copy function, as follows.

BaseType* DerivedType::copy () { return new DerivedType(*this); }

If your BaseType isn't a virtual base class, then you'd define
copy in the base class to return new BaseType(*this).

This is simple; it calls the copy constructor for the appropriate type
to do the copy.  This assumes either that the default copy constructor
will do, or that you've defined copy constructors when they won't.


--
Joe Buck
jbuck@ohm.berkeley.edu	 {uunet,ucbvax}!ohm.berkeley.edu!jbuck	

roger@procase.UUCP (Roger H. Scott) (05/05/90)

In article <1019@rna.UUCP> kc@rna.UUCP (Kaare Christian) writes:
>I recently needed to make a copy (a clone) of a class object, given only a
>base class pointer to the object.  C++ lets you do some things with a class,
>knowing only its base type, but it doesn't provide an easy way to make
>a copy.
I suppose that depends almost entirely on how you define "easy".  Do you
mean something easier than the following?:

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

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

    ...

    Base *p = ...;
    Base *another_just_like_p = p->clone();
    
>...
>One way might be to add a clone facility, that would be used equivalently
>to new, but that would duplicate an existing object.
The problem here is the word "duplicate".  It is rarely the case that a logical
"clone" of an object is simply a bit-wise copy (a.k.a. shallow copy).  Sometimes
what you want is a clone of an entire structure (a.k.a deep copy).
>	Base *p = ... ;
>	Base *b;
>	b = clone *p; // new takes a type, clone takes an object
>
>Another method might be to have a typeof builtin, perhaps similar to the
>following:
>	Base *p = .... ;
>	Base *b;
>	b = new typeof(*p);	// allocates space
>	*(typeof(*p) *)b = *(typeof(*p) *)p;	// ugly, but copies whole thing
Both of these schemes suffer from the same problem: *in general*, a C++ compiler
does not know the type of the object that a pointer points to.  In order to fix
this the definition of the language would have to be changed so that *all*
objects were guaranteed to encode their own type in some manner or other.  The
fact that this is not so is not immediately obvious from the language definition
(as opposed to from well-known implementations), but it can be inferred from the
conformance of C++ structs to C structs and the equivalence of C++ classes to
C++ structs.  I.M.H.O. the biggest mistake made in the design of C++ was the
equivalence of classes and structs.

horstman@sjsumcs.sjsu.edu (Cay Horstmann) (05/05/90)

In article <1019@rna.UUCP> kc@rna.UUCP (Kaare Christian) writes:
>I recently needed to make a copy (a clone) of a class object, given only a
>base class pointer to the object.  C++ lets you do some things with a class,
>knowing only its base type, but it doesn't provide an easy way to make
>a copy.  My solution was to make a virtual member function that
>returned the size of each of the derived classes, and then make an
>operator= function (left arg, ref pointer to base, right arg, ref to
>base) that did the work - it called the size fn of the right operand to
>determine how much space was needed, allocated it, did a bitwise copy,
>then did some housekeeping.
>
That appears to be a very dangerous thing to do in general. Many classes
need more than bitwise copying for correct behavior (e.g. when using
ref counts.) What if someone derives from your stuff, faithfully supplies
the size function and adds a data member with nontrivial copy semantics?

Cay