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

Polymorphism and std::copy

63 views
Skip to first unread message

Doug Mika

unread,
Apr 20, 2015, 4:59:05 PM4/20/15
to
Hi

I have a base class called Fish, from this base class I derive two classes called Tuna and Carp

I create a vector<Fish> into which I place new objects of Tuna and Carp.
ie
vector<Fish> vecOfFish;
vecOfFish.push_back(new Tuna());
vecOfFish.push_back(new Carp());
...

Now I want to create a second vector of Fish
vector<Fish> vecOfFish2;

and copy the first vector into the second using std::copy.

Which methods (copy constructor, copy assignment operator,....) must Carp and Tuna implement for the std::copy function to work properly (to perform a deep copy on my vector)?

Mr Flibble

unread,
Apr 20, 2015, 5:23:57 PM4/20/15
to
On 20/04/2015 21:58, Doug Mika wrote:
> Hi
>
> I have a base class called Fish, from this base class I derive two classes called Tuna and Carp
>
> I create a vector<Fish> into which I place new objects of Tuna and Carp.
> ie
> vector<Fish> vecOfFish;

I think you meant vector<Fish*> but use vector<std::unique_ptr<Fish>>
instead so you don't have to worry about memory leaks.

> vecOfFish.push_back(new Tuna());
> vecOfFish.push_back(new Carp());
> ...
>
> Now I want to create a second vector of Fish
> vector<Fish> vecOfFish2;
>
> and copy the first vector into the second using std::copy.
>
> Which methods (copy constructor, copy assignment operator,....) must Carp and Tuna implement for the std::copy function to work properly (to perform a deep copy on my vector)?

A naked pointer doesn't have any methods so it is not possible using
std::copy on the vector to do a "deep" copy; perhaps use std::transform
instead sausages.

/Flibble


Paavo Helde

unread,
Apr 20, 2015, 5:28:22 PM4/20/15
to
Doug Mika <doug...@gmail.com> wrote in
news:3bd1a60e-b37a-45c9...@googlegroups.com:

> Hi
>
> I have a base class called Fish, from this base class I derive two
> classes called Tuna and Carp
>
> I create a vector<Fish> into which I place new objects of Tuna and
> Carp. ie
> vector<Fish> vecOfFish;
> vecOfFish.push_back(new Tuna());
> vecOfFish.push_back(new Carp());

This does not compile. You have defined a vector of Fish objects, but are
pushing in pointers to objects instead of objects.

For getting polymorphic behavior you need a vector of some kind of
pointers. Instead of plain pointers better consider some kind of smart
pointers, e.g.

vector<std::shared_ptr<Fish>> vecOfFish;
vecOfFish.push_back(std::shared_ptr<Fish>(new Tuna()));
vecOfFish.push_back(std::shared_ptr<Fish>(new Carp()));


> ...
>
> Now I want to create a second vector of Fish
> vector<Fish> vecOfFish2;
>
> and copy the first vector into the second using std::copy.
>
> Which methods (copy constructor, copy assignment operator,....) must
> Carp and Tuna implement for the std::copy function to work properly
> (to perform a deep copy on my vector)?

For deep copy one needs to duplicate all the Tuna and Carp objects, given
only pointers to Fish. One typically implements this by declaring a
virtual clone function (look this up) in the base class. Both Carp and
Tuna must implement this and return a (smart)pointer to the cloned
object. The clone functions will typically make use of the copy
constructors.

std::copy() is probably not enough for getting deep copy (unless you use
a specific deep-copying smartpointer which does not seem very practical
otherwise). You will need to write a custom loop or use something like
std::transform().

hth
Paavo
Message has been deleted

Christopher Pisz

unread,
Apr 20, 2015, 6:54:27 PM4/20/15
to
On 4/20/2015 5:24 PM, Stefan Ram wrote:
SNIP

> The following code shows a deep copy of a vector of pointers
> /without/ ::std::copy (not fully tested).
>
> #include <iostream>
> #include <ostream>
> #include <memory>
> #include <vector>
>
> struct Fish
> { virtual void print() = 0;
> virtual ::std::unique_ptr< Fish >clone() = 0; };
>
> class Tuna : public Fish
> { void print () override { puts( "Tuna" ); }
> ::std::unique_ptr< Fish >clone () override
> { return ::std::make_unique< Tuna >( *this ); }};
>
> class Carp : public Fish
> { void print () override { puts( "Carp" ); }
> ::std::unique_ptr< Fish >clone () override
> { return ::std::make_unique< Carp >( *this ); }};
>
> int main()
> { ::std::vector< ::std::unique_ptr< Fish >> v;
> v.push_back( ::std::make_unique< Tuna >() );
> v.push_back( ::std::make_unique< Carp >() );
> ::std::vector< ::std::unique_ptr< Fish >> w;
> for( auto & f: v )w.push_back( f->clone() ); /* copying is here */
> for( auto & f: w )f->print(); }
>
>

Still catching up on the C++11 standard.

What do the override and final keywords actually accomplish? Is its only
purpose to provide compiler errors if the base didn't have a matching
virtual method signature? Or does it do something else, perhaps some
kind of optimization?


--
I have chosen to troll filter/ignore all subthreads containing the
words: "Rick C. Hodgins", "Flibble", and "Islam"
So, I won't be able to see or respond to any such messages
---

Luca Risolia

unread,
Apr 20, 2015, 7:06:19 PM4/20/15
to
Il 20/04/2015 23:28, Paavo Helde ha scritto:
> vector<std::shared_ptr<Fish>> vecOfFish;
> vecOfFish.push_back(std::shared_ptr<Fish>(new Tuna()));
> vecOfFish.push_back(std::shared_ptr<Fish>(new Carp()));

Use std::make_shared() whenever possible. It's more efficient and more
compact (in terms of both object and source code).

In this case:
vecOfFish.push_back(std::make_shared<Tuna>());
vecOfFish.push_back(std::make_shared<Carp>());

Message has been deleted

Melzzzzz

unread,
Apr 20, 2015, 10:23:24 PM4/20/15
to
On 21 Apr 2015 01:36:10 GMT
r...@zedat.fu-berlin.de (Stefan Ram) wrote:

> r...@zedat.fu-berlin.de (Stefan Ram) writes:
> >struct Fish
> >{ virtual void print() = 0;
> > virtual ::std::unique_ptr< Fish >clone() = 0; };
> >class Tuna : public Fish
> >{ void print () override { puts( "Tuna" ); }
> ...
> >for( auto & f: w )f->print(); }
>
> I only now become aware of the fact that the
> »print« method of »Tuna« is called by the client,
> even though it is »privat« in »class Tuna«!
> Or does it »inherit« the »public«?
>
> I wanted to make »print« public, but forgot to
> make it public in »class Tuna«.
>
> Is this good or bad style?
>

Well, one can't call print on Tuna but can on Fish.
I remember it was considered to be good style to make virtual functions
private and call them from base class non virtual functions eg:

class Base {
public:
void f() {
virt();
}
}
private:
virtual void virt()=0;
};

class Derived : public Base {
void virt() {}
};

Derived d; d.f();


Victor Bazarov

unread,
Apr 21, 2015, 12:04:12 AM4/21/15
to
Given 'class Derived : public Base {};', is 'shared_ptr<Derived>'
convertible to 'shared_ptr<Base>'? Your suggestion seems to imply as
much...

V
--
I do not respond to top-posted replies, please don't ask

Ian Collins

unread,
Apr 21, 2015, 12:46:17 AM4/21/15
to
Christopher Pisz wrote:
>
> Still catching up on the C++11 standard.
>
> What do the override and final keywords actually accomplish? Is its only
> purpose to provide compiler errors if the base didn't have a matching
> virtual method signature? Or does it do something else, perhaps some
> kind of optimization?

Mainly the former.

It also provides a better form of documentation than prefixing virtual
function overrides with "virtual" as required by some older coding
standards I've sen.

--
Ian Collins

Paavo Helde

unread,
Apr 21, 2015, 1:00:56 AM4/21/15
to
Christopher Pisz <nos...@notanaddress.com> wrote in news:mh400q$r4o$1@dont-
email.me:

>
> What do the override and final keywords actually accomplish? Is its only
> purpose to provide compiler errors if the base didn't have a matching
> virtual method signature? Or does it do something else, perhaps some
> kind of optimization?

The final keyword can be used for optimization as the compiler can
potentially replace some virtual calls by non-virtual and maybe even inline
them. However, I guess this is not the main reason because if this is
possible it means that making the function virtual was not really necessary
in the first place (at least not in this usage scenario).

The override keyword is just for producing compiler errors, but it is
immensely useful when refactoring a large code base. I guess final could
also be useful in some kind of (more radical) refactoring.

Cheers
Paavo

Paavo Helde

unread,
Apr 21, 2015, 1:30:59 AM4/21/15
to
r...@zedat.fu-berlin.de (Stefan Ram) wrote in news:private-20150421033347
@ram.dialup.fu-berlin.de:

> r...@zedat.fu-berlin.de (Stefan Ram) writes:
>>struct Fish
>>{ virtual void print() = 0;
>> virtual ::std::unique_ptr< Fish >clone() = 0; };
>>class Tuna : public Fish
>>{ void print () override { puts( "Tuna" ); }
> ...
>>for( auto & f: w )f->print(); }
>
> I only now become aware of the fact that the
> »print« method of »Tuna« is called by the client,
> even though it is »privat« in »class Tuna«!
> Or does it »inherit« the »public«?
>
> I wanted to make »print« public, but forgot to
> make it public in »class Tuna«.
>
> Is this good or bad style?

Yes, you can have private virtual functions in C++. The access checks are
done at compile time only and are based on the static type of the
pointer/reference through which the virtual function is called. At run-
time the program does not know or care any more if some vtable slot
points to a private or non-private virtual function override.

This is most useful if the access is uniformly private in all classes of
the hierarchy. In your example (public in the base, private in derived)
it is just a bit confusing and does not accomplish much. But according to
the ideology of C++, a half-accidental language feature like this is not
locked down just because there is no clear usage case or it could be
potentially misused. Instead, the programmer is trusted to use or not use
the features as he sees fit.

Cheers
Paavo

Richard

unread,
Apr 21, 2015, 11:30:13 AM4/21/15
to
[Please do not mail me a copy of your followup]

Luca Risolia <luca.r...@linux-projects.org> spake the secret code
<mh40ot$9p0$1...@speranza.aioe.org> thusly:
Even better: if you just need a container of polymorphic objects use
std::unique_ptr<T> and std::make_unique[*].

I see people over-usign shared_ptr when unique_ptr would suffice.

[*] if your implementation doesn't yet have make_unique or unique_ptr,
then consider using an alternative from boost.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

Luca Risolia

unread,
Apr 21, 2015, 12:16:56 PM4/21/15
to
On 21/04/2015 17:29, Richard wrote:
>>> vecOfFish.push_back(std::shared_ptr<Fish>(new Tuna()));
>>> vecOfFish.push_back(std::shared_ptr<Fish>(new Carp()));
>>
>> Use std::make_shared() whenever possible. It's more efficient and more
>> compact (in terms of both object and source code).
>>
>> In this case:
>> vecOfFish.push_back(std::make_shared<Tuna>());
>> vecOfFish.push_back(std::make_shared<Carp>());
>
> Even better: if you just need a container of polymorphic objects use
> std::unique_ptr<T> and std::make_unique[*].

If it's better clearly depends on the real application. unique_ptr's are
inadequate, if you need to copy the vector for some reasons.

Mr Flibble

unread,
Apr 21, 2015, 12:33:40 PM4/21/15
to
On 21/04/2015 16:29, Richard wrote:
[snip]

> I see people over-usign shared_ptr when unique_ptr would suffice.
>
> [*] if your implementation doesn't yet have make_unique or unique_ptr,
> then consider using an alternative from boost.
>

There is no alternative to unique_ptr in Boost as unique_ptr requires
move semantics and Boost won't magically give you move semantics sausages.

/Flibble
Message has been deleted

Luca Risolia

unread,
Apr 21, 2015, 2:23:10 PM4/21/15
to
Il 21/04/2015 06:03, Victor Bazarov ha scritto:

> Given 'class Derived : public Base {};', is 'shared_ptr<Derived>'
> convertible to 'shared_ptr<Base>'?

Yes, although they are not covariant.


0 new messages