Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Copying varied types

0 views
Skip to first unread message

Pat

unread,
Nov 24, 2009, 6:36:51 PM11/24/09
to
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...

Balog Pal

unread,
Nov 24, 2009, 7:11:58 PM11/24/09
to
"Pat" <n...@e-mail.com>

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

LR

unread,
Nov 24, 2009, 7:23:46 PM11/24/09
to
Pat wrote:
> 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

0 new messages