Copying varied types

P

Pat

Hi c.l.c++,

Suppose I have a fairly complex class hierarchy. All
the classes in the hierarchy have "child" pointers (one
or more) so that a big tree of these objects can be
built. But the catch is that each node in the tree can
be any type (in the hierarchy).

Now, I want to write a function to walk that tree and
create an exact copy of it. It's ok to assume that the
tree contains no loops.

I could write a fairly simple recursive function that
1) allocates a new object, 2) copies the old node's
data, and 3) calls itself for each child in the old
node.

But the trouble is in step 1, because I don't know what
type to allocate... My first thought was to use a
templated "clone" function, something like so:

template <class T>
T *clone(T *source)
{
T *dest = new T;

dest->x = source->x;
dest->y = sourec->y;
dest->z = source->z;

return dest;
}

But that doesn't work because as I'm walking the tree,
all of the "child" pointers are the same type (the base
class). And when I call clone() with a pointer to the
base class, it returns a pointer to the base class.

So, then, I thought that each derived class should have
a virtual clone() function that returns the appropriate
type. But then there's no way to call the correct
function at run-time. Each class's clone() function
would have a different return type.

I could have some sort of switch statement, I guess,
but that's ugly...
 
B

Balog Pal

Pat said:
Now, I want to write a function to walk that tree and
create an exact copy of it. It's ok to assume that the
tree contains no loops.

I could write a fairly simple recursive function that
1) allocates a new object, 2) copies the old node's
data, and 3) calls itself for each child in the old
node.

But the trouble is in step 1, because I don't know what
type to allocate...

You do: same type as the one you copy.
My first thought was to use a > templated "clone" function

No fly.
So, then, I thought that each derived class should have
a virtual clone() function that returns the appropriate
type.

Yeah. clone() certainly does all the job you describe above, and the copy is
invoked by the topmost node->clone();

clone() normally is nothing but {return new tSelf( *original);} and can be
injected by a macro along with other cool functions supporting hierarchy
build and serialization (where you normally need a static Create( Key )
function that you register with a factory, and virtual GetKey()... When
reading from file you really need to create the object from the thin air. )

The copy ctor of leafs can be left the factory one, if you implement the
child collection managenemt in the Root base class...
But then there's no way to call the correct
function at run-time. Each class's clone() function
would have a different return type.

Actually you can use covariant types -- each function returning tSelf *,
that doesn't spoil the virtual game -- but for your purpose it is no problem
if Root * is returned everywhere. You don't call anything on that pointer
anyway, just put in in the collection...
I could have some sort of switch statement, I guess,
but that's ugly...

I wouldn't suggest unless you have a fixed number of classes that will not
change in the lifetime of the program. (kinda rare case... ;)
 
L

LR

Pat said:
Hi c.l.c++,

Suppose I have a fairly complex class hierarchy. All
the classes in the hierarchy have "child" pointers (one
or more) so that a big tree of these objects can be
built. But the catch is that each node in the tree can
be any type (in the hierarchy).

Do they all inherit from the same base?

Now, I want to write a function to walk that tree and
create an exact copy of it.



I could write a fairly simple recursive function that
1) allocates a new object, 2) copies the old node's
data, and 3) calls itself for each child in the old
node.

Sounds like you want to call new with a copy ctor,
BaseClass *p1 = new SomeClass;
BaseClass *p2 = new SomeClass(*p1);

But the trouble is in step 1, because I don't know what
type to allocate...

Each clone function can return a pointer to the base class.
My first thought was to use a
templated "clone" function, something like so:

template <class T>
T *clone(T *source)
{
T *dest = new T;

dest->x = source->x;
dest->y = sourec->y;
dest->z = source->z;

return dest;
}

But that doesn't work because as I'm walking the tree,
all of the "child" pointers are the same type (the base
class). And when I call clone() with a pointer to the
base class, it returns a pointer to the base class.

Then consider a member function like this:

BaseClass *SomeClass::clone() const { return new SomeClass(*this); }
So, then, I thought that each derived class should have
a virtual clone() function that returns the appropriate
type. But then there's no way to call the correct
function at run-time. Each class's clone() function
would have a different return type.

If your compiler supports covariant return types then you can make the
pointer returned from each of the classes that inherit from your base
class a pointer to the particular class, so something like:

In your BaseClass

virtual BaseClass *clone() const { return new BaseClass(*this); }

and in a class that inherits from BaseClass

SomeClass *clone() const { return new SomeClass(*this); }

I could have some sort of switch statement, I guess,
but that's ugly...

It would be. And hard to maintain too.

If this doesn't help you, you might want to look into something like
boost::variant.

LR
 

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

Forum statistics

Threads
473,755
Messages
2,569,539
Members
45,024
Latest member
ARDU_PROgrammER

Latest Threads

Top