Cloning members of a hierarchy

P

Paul N

I've got various classes derived (directly or indirectly) from a
single base, and want a function to make a copy of a given object. My
code is along the following lines:

class Base {
public:
int b;
virtual Base *clone() = 0;
};

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

Am I right in thinking that I need to include a definition of the
"clone" function for every class that I want to be able to clone
objects of? And that this would be true even if I didn't make it a
pure virtual function? And that there is no easy way round this, short
of using macros to "tidy" the code up? But conversely, am I right in
thinking that the automatically-generated copy constructors will do
the actual donkey work of making a copy of all the members at all the
levels for me?

(I was also going to include a question about a potential bug in VC++,
in which it complained about not being able to instatiate an abstract
class - but it turned out that the problem was that one declaration
was declared "const" and the other wasn't, so it was my fault.)

Thanks.
Paul.
 
V

Victor Bazarov

Paul said:
I've got various classes derived (directly or indirectly) from a
single base, and want a function to make a copy of a given object. My
code is along the following lines:

class Base {
public:
int b;
virtual Base *clone() = 0;
};

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

Am I right in thinking that I need to include a definition of the
"clone" function for every class that I want to be able to clone
objects of?

Yes. In production code I often see a macro that does that. Don't
forget to write it in your class. Something like

#define DEFINE_CLONABLE(class_name) class_name* clone() \
{ return new class_name(*this); }

....
class Derived ...
DEFINE_CLONABLE(Derived)
};
> And that this would be true even if I didn't make it a
pure virtual function?

If you didn't make it pure virtual, what would its body look like?
> And that there is no easy way round this, short
of using macros to "tidy" the code up?

Not really. Unless I'm missing something obvious, of course.
> But conversely, am I right in
thinking that the automatically-generated copy constructors will do
the actual donkey work of making a copy of all the members at all the
levels for me?

Seems so.
(I was also going to include a question about a potential bug in VC++,
in which it complained about not being able to instatiate an abstract
class - but it turned out that the problem was that one declaration
was declared "const" and the other wasn't, so it was my fault.)

That would certainly do it. :)

V
 
R

Robert Fendt

I've got various classes derived (directly or indirectly) from a
single base, and want a function to make a copy of a given object. My
code is along the following lines:

class Base {
public:
int b;
virtual Base *clone() = 0;
};

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

Am I right in thinking that I need to include a definition of the
"clone" function for every class that I want to be able to clone
objects of? And that this would be true even if I didn't make it a
pure virtual function? And that there is no easy way round this, short
of using macros to "tidy" the code up?

You can use a template. Without having it run through a compiler, something like this could/should work:

class Base
{
public:
virtual Base* clone() = 0;
};

template <typename T>
class ClonableBase : public Base
{
public:
virtual Base* clone()
{
return new T(*this);
}
}

class Derived: public ClonableBase<Derived>
{
....
};

This should work since every derived class inherits its own implementation of clone() from a template-generated 'buffer' class. However, I do not see much to be gained by this. Just implement the virtual constructors in the derived classes, that way at least the semantics become immediately clear.
But conversely, am I right in
thinking that the automatically-generated copy constructors will do
the actual donkey work of making a copy of all the members at all the
levels for me?

This works if your class looks more or less like a traditional C struct (i.e. a POD type, or 'plain old data'). However, be very, very careful if the constructor performs resource aquisition (and the destructor therefore frees resources). Then it will most probably NOT work, and can even lead to double-deletes and such pains.

As a rule, if your class contains at least one of the following, it will most probably need all three: destructor, copy constructor, assignment operator. In general do no depend on the generated versions, except in very simple cases; they have a tendency to not do what you want or need.
(I was also going to include a question about a potential bug in VC++,
in which it complained about not being able to instatiate an abstract
class - but it turned out that the problem was that one declaration
was declared "const" and the other wasn't, so it was my fault.)

Yes. C++ currently lacks an 'override' keyword (C++ 0x will get it, though), so you cannot tell the compiler that a function is supposed to override a function in the base class. This means that the compiler cannot give a meaningful error message, since it would have to 'guess' what yo actually want to achieve. That said, the Microsoft compiler _does_ support an override modifier as an extension. However, using non-standard extensions lead to non-portable code.

Robert
 
P

Paul N

(snip)


Yes.  In production code I often see a macro that does that.  Don't
forget to write it in your class.  Something like

#define DEFINE_CLONABLE(class_name) class_name* clone() \
                                     { return new class_name(*this); }

...
    class Derived ...
      DEFINE_CLONABLE(Derived)
    };

Interesting. I thought macros were generally disapproved of? I'll have
a think as to whether to do it this way.
 > And that this would be true even if I didn't make it a


If you didn't make it pure virtual, what would its body look like?

At one stage the body (in the base class, which was abstract due to
another pure virtual function) was { return NULL; } which satisfied
the compiler. A horrible kludge, though, and I'm glad it's gone.

(more snip)

Thanks for the help!
Paul.
 
P

Paul N

You can use a template. Without having it run through a compiler, something like this could/should work:

class Base
{
public:
  virtual Base* clone() = 0;

};

template <typename T>
class ClonableBase : public Base
{
public:
  virtual Base* clone()
  {
    return new T(*this);
  }

}

class Derived: public ClonableBase<Derived>
{
...

};

So far I haven't learnt anyhting about templates, but this is further
evidence that it would be a good idea if I did.
This should work since every derived class inherits its own implementation of clone() from a template-generated 'buffer' class. However, I do not see much to be gained by this. Just implement the virtual constructors in the derived classes, that way at least the semantics become immediately clear.


This works if your class looks more or less like a traditional C struct (i.e. a POD type, or 'plain old data'). However, be very, very careful if the constructor performs resource aquisition (and the destructor therefore frees resources). Then it will most probably NOT work, and can even lead to double-deletes and such pains.

As a rule, if your class contains at least one of the following, it will most probably need all three: destructor, copy constructor, assignment operator. In general do no depend on the generated versions, except in very simple cases; they have a tendency to not do what you want or need.

Ah. I knew about the "rule of three". But you saying it makes me
realise that my class does in fact have a memory leak, one which I'd
totally overlooked before.
Yes. C++ currently lacks an 'override' keyword (C++ 0x will get it, though), so you cannot tell the compiler that a function is supposed to override a function in the base class. This means that the compiler cannot give a meaningful error message, since it would have to 'guess' what yo actually want to achieve. That said, the Microsoft compiler _does_ support an override modifier as an extension. However, using non-standard extensions lead to non-portable code.

Many thanks for your help.
Paul.
 
R

Robert Fendt

So far I haven't learnt anyhting about templates, but this is further
evidence that it would be a good idea if I did.

Templates are an integral part of modern C++, so you really should familiarise yourself with them. However, be aware that templates form a complete declarative meta-language. It is a lot like functional programming (just not on data but on types), and can get complicated quite quickly. Templates are difficult to read, and some of the compiler-errors produced by erroneous templates are more or less impossible to decipher. So start with simple cases. The most important thing to remember is that a C++ template is _not_ the same as generics in Java or C#. A template produces no code, unless it is 'instantiated' with the corresponding type or constant. Only than does the compiler produce code, not before.

The example I have shown is in fact not a 'simple' case, since the template receives the type of the inheriting class as its parameter (yes, that's legal). So each inheriting class is derived from its specific super class, which in turn inherits from the base class (and is generated automatically from the template). Stuff like that really can make the brain hurt if one is not used to it... at least it was like that for me.

Robert
 

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,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top