copy ctor question

S

scooter

Given this class heirarchy

class Base{};

class A : public Base
{};

class B : public Base
{};

etc

How do I go about coding a copy ctor for the following class:

class SomeClass
{
std::vector<Base*> m_BasePointers;
};

when m_BasePointers contains pointers to child classes of Base?




thanks
 
A

Attila Feher

scooter said:
Given this class heirarchy

class Base{};

class A : public Base
{};

class B : public Base
{};

etc

How do I go about coding a copy ctor for the following class:

class SomeClass
{
std::vector<Base*> m_BasePointers;
};

when m_BasePointers contains pointers to child classes of Base?

Do you want to copy what Base* points to? Well, that is not very simple...
I mean it is, but forcing it work isn't (you cannot force people to write
correct code).

// I hope you have meant:
class Base{
virtual ~Base();
};

// Now let's add a clone function:
class Base{
virtual ~Base();
virtual Base *Clone() const {
return new Base(*this);
}
};


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

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

The trouble with that is that if someone forgets to write his clone in a
derived class you get slicing. :-(

Now all you need to do is to use Base::Clone() to copy the elements.

Some please add testing using the RTTI into the base class(es) to check if
*this is actually a Base when the function is called. If not, they assert
(abort).
 
U

Unforgiven

scooter said:
Given this class heirarchy

class Base{};

class A : public Base
{};

class B : public Base
{};

etc

How do I go about coding a copy ctor for the following class:

class SomeClass
{
std::vector<Base*> m_BasePointers;
};

when m_BasePointers contains pointers to child classes of Base?

I'm assuming you want the Base-derived objects to be copied in the process?
Because if just copying the pointer values is what you want the copy
constructor of std::vector should already do the trick.

Your best option (IMHO) is probably to give Base a 'clone' function, that
you implement in A and B to create new (equivalent) As and Bs, and use that
in the copy constructor of SomeClass:

<code>
class Base
{
public:
virtual Base* Clone() const = 0;
};

class A : public Base
{
public:
A(A &a) { /*copy const for A*/ }
virtual Base* Clone() const
{
/* Caller must delete pointer! */
return new A(*this);
}
};

/* Same for B as for A */
</code>

Writing the copy constructor should be easy then.
 
R

Ralf Schneeweiß

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

Well, your solution is the prototype pattern. A good idea can be the
implementation of the copy-constructor, because you are using it:


class B : public Base
{
public:
B( const B& b )
{
...
}

virtual B *Clone() const{
return new B(*this); // Here the copy-constructor is used.
}
};


Ralf


http://www.oop-trainer.de
 
A

Attila Feher

Ralf said:
Well, your solution is the prototype pattern. A good idea can be the
implementation of the copy-constructor, because you are using it:

And since the class contains absolutely no managed resources the copy
constructor syntetized by the compiler is just fine.
 
R

Ralf Schneeweiß

The solution described by Attila Feher is the prototype pattern of the GoF.
The idea is to give a polymorphic (virtual) method, which can create a copy
of your polymorphic object. The problem is, that a constructor never can be
virtual.
You have to call it by its correct name, which ist the class name. Copying a
polymorphic object with the constructor would force you to find out the
object type
before you are copying. This is the reason for the virtual clone() method.
A good idea is to use the copy-constructor inside the clone() method.


Ralf

http://www.oop-trainer.de
 
A

Attila Feher

Ralf said:
The solution described by Attila Feher is the prototype pattern of
the GoF. The idea is to give a polymorphic (virtual) method, which
can create a copy of your polymorphic object.

It is very similar, but the motivation is completely different. Therefore
it looks like the Prototype pattern, but it isn't. One reason for that is
that it is not used to provide copies of prototypes.
The problem is, that a constructor never can be virtual.

Which does not matter for use, since we use polymorphic behavior, so we do
not work with constructors directly.
You have to call it by its correct name,
which ist the class name.

Which does not apply here, since we do not know the class name.
Copying a polymorphic object with the constructor would
force you to find out the object type before you are copying.
This is the reason for the virtual clone()
method. A good idea is to use the copy-constructor inside the clone()
method.

It *is* using the copy constructor.
 
H

Howard

Attila Feher said:
It is very similar, but the motivation is completely different. Therefore
it looks like the Prototype pattern, but it isn't. One reason for that is
that it is not used to provide copies of prototypes.


Which does not matter for use, since we use polymorphic behavior, so we do
not work with constructors directly.


Which does not apply here, since we do not know the class name.


It *is* using the copy constructor.

I think you're misunderstanding Ralf's intention. If *I'm* understanding it
correctly, he's not disagreeing with you, but rather providing an
explanantion as to why yours is a good solution. At least, that's what I
got out of it. (The statement "the problem is..." isn't a complaint about
your solution, but an explanantion of the problem that *led* to the
solution.) Ralf, forgive me if I'm wrong, but that is what you meant, isn't
it?

(BTW, what's "GoF"???)

-Howard
 
L

lilburne

Attila said:
And since the class contains absolutely no managed resources the copy
constructor syntetized by the compiler is just fine.

Keep the copy ctor, because you'll probably end up adding
data to the class, and at sometime you'll have a debugging
session where you'll want to know when the damn thing is
copy conbstructed.

Kick out the inlines though, virtual inlines are definitely
a mistake, and the rest are a waste of time, and only serve
to clutter your headers with implementation details.
 
W

WW

Again: it is not the Prototype pattern, it just happens to look like it.
The motivation of the Protoype pattern is completely different from the
motivation here. The things this code copies are not prototypes.
Keep the copy ctor, because you'll probably end up adding
data to the class, and at sometime you'll have a debugging
session where you'll want to know when the damn thing is
copy conbstructed.

Big mistake. Huge mistake. Adding a copy constructor to a class having no
controlled resources is a mistake. It's copy constructor will be identical
to the one generated by the compiler - at best. However it introduces
maintenance risk and nightmare for no value.

If someone needs to know when a class is copied that person can look at the
language definition. Or make a small, 15 lines test program if unsure. BTW
copy constructors with side effects are rarely a good idea.
Kick out the inlines though, virtual inlines are definitely
a mistake, and the rest are a waste of time, and only serve
to clutter your headers with implementation details.

Have you looked at the language definition lately? I do not recall virtual
inlines being a mistake. And writing things inline in an untested example
code does not mean that they have to be written inline in real code
either...

BTW such a clone function is "final". So making it inline is not a mistake.
Although in this case adds not much, since such a function will only be
called via a pointer to (some) base. For this (by you unmentioned) reason
it makes sense not to make them inline. BTW I hope you did know that
virtual functions (if the dynamic type is known compile time) *can* be
inlined.
 
R

Ralf Schneeweiß

I think you're misunderstanding Ralf's intention. If *I'm* understanding it
correctly, he's not disagreeing with you, but rather providing an
explanantion as to why yours is a good solution. At least, that's what I
got out of it. (The statement "the problem is..." isn't a complaint about
your solution, but an explanantion of the problem that *led* to the
solution.) Ralf, forgive me if I'm wrong, but that is what you meant, isn't
it?

(BTW, what's "GoF"???)

-Howard


You are right. My English is not so good and possibly I am using
some words sometimes in a displaced manner.
Sorry for it.

Ralf
 
L

lilburne

WW said:
Again: it is not the Prototype pattern, it just happens to look like it.
The motivation of the Protoype pattern is completely different from the
motivation here. The things this code copies are not prototypes.




Big mistake. Huge mistake. Adding a copy constructor to a class having no
controlled resources is a mistake. It's copy constructor will be identical
to the one generated by the compiler - at best. However it introduces
maintenance risk and nightmare for no value.

Illustrate one!
If someone needs to know when a class is copied that person can look at the
language definition. Or make a small, 15 lines test program if unsure. BTW
copy constructors with side effects are rarely a good idea.

Only a putz doesn't know the circumstances of when the
language definition dictates that a copy constructor is
called. But that is different from discovering where a copy
ctor is being called from. You can't put a break point on a
complier generated method.
Have you looked at the language definition lately? I do not recall virtual
inlines being a mistake. And writing things inline in an untested example
code does not mean that they have to be written inline in real code
either...

The language definition also has gotos.
BTW such a clone function is "final". So making it inline is not a mistake.


How many versions of the method do you end up with?

Although in this case adds not much, since such a function will only be
called via a pointer to (some) base. For this (by you unmentioned) reason
it makes sense not to make them inline.

How many versions get injected into the object file?

BTW I hope you did know that
virtual functions (if the dynamic type is known compile time) *can* be
inlined.

Gosh you don't say. You mean that if one writes:

Derived d;
Base& b = d;
b.virtual_method();

the virtual method it might get inlined? Hot damn wonders
upon wonders, such a marvelous feature.
 
W

WW

lilburne said:
Illustrate one!

If you ask me nicely.
Only a putz doesn't know the circumstances of when the
language definition dictates that a copy constructor is
called.
???

But that is different from discovering where a copy
ctor is being called from. You can't put a break point on a
complier generated method.
???


The language definition also has gotos.

Yes. And they also have their use.
How many versions of the method do you end up with?

Versions???? Of Clone()? One per class.
How many versions get injected into the object file?

None or one. Why do you care?
Gosh you don't say. You mean that if one writes:

Derived d;
Base& b = d;
b.virtual_method();

the virtual method it might get inlined? Hot damn wonders
upon wonders, such a marvelous feature.

It might. But this was not the case I was talking about.
 
L

lilburne

jeffc said:
Why do you say that?

If the method is virtual then you will normally be calling
it via base some class, in other words you'll be using late
binding. In such cases the compiler can't inline the call
because it doesn't know which derived class version of the
method to inject. Therefore, it uses the virtual calling
mechanism so your virtual method is not inlined. Secondly
the compiler needs to have a method to call so it injects a
static version of the method into the object file created by
each source file that reads the header, you might also get a
copy of the classes vtable injected into the object file too.

Using inlines in general is a bit like writing:

if (expression) some_statement;

Try putting a break point on some_statement. Try puting a
break point on an inline method. You might be able to step
into one but you wont be able to break when the method is
called.

In some cases where a method is small and heavily used then
inline will give some performance benefit. But the cases
where that is so is pretty limited.

Then there is the obsfucation of the inline methods
cluttering up the class header files. When inlining is
heavily used the classes API becomes obscured, and when an
inline method is altered the world has to recompile.
 
R

Rolf Magnus

Howard said:
(BTW, what's "GoF"???)

It means "Gang of Four" and refers to the book "Design Patterns", which
was written by a "Gang of Four" authors Erich Gamma, Richard Helm,
Ralph Johnson and John Vlissides.
 
W

WW

lilburne said:
LOL - such naivety.

Why is it so that all AOL born troll must use LOL when they run out of
arguments?

I am not naive. I use build systems as opposed to hoping to get a build
right. And yes. For my projects ODR seems not to be violated. And guess
what. It is not because of chanting or magic rules, such as: do not use
inlines. It probably has to do more with knowing what you are doing.
 

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

Similar Threads


Members online

No members online now.

Forum statistics

Threads
474,145
Messages
2,570,824
Members
47,369
Latest member
FTMZ

Latest Threads

Top