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

new Class(*this)

73 views
Skip to first unread message

Doug Mika

unread,
Apr 8, 2015, 4:28:26 PM4/8/15
to
I have the following two classes:

class Fish{
public:
virtual Fish* Clone()=0;
virtual void Swim()=0;
};

class Tune:public Fish{
public:
Fish* Clone(){
return new Tuna(*this);
}

void Swim(){
cout<<"Tuna swims fast in the sea"<<endl;
}
};

my question is, what is new Tuna(*this) when Tuna doesn't define a constructor that takes a parameter. It only has the default parameterless constructor! So what is: new Tuna(*this);

Much thanks
Doug

Victor Bazarov

unread,
Apr 8, 2015, 4:39:42 PM4/8/15
to
On 4/8/2015 4:28 PM, Doug Mika wrote:
> I have the following two classes:
>
> class Fish{
> public:
> virtual Fish* Clone()=0;
> virtual void Swim()=0;
> };
>
> class Tune:public Fish{

class Tuna:public Fish{

> public:
> Fish* Clone(){
> return new Tuna(*this);
> }
>
> void Swim(){
> cout<<"Tuna swims fast in the sea"<<endl;
> }
> };
>
> my question is, what is new Tuna(*this) when Tuna doesn't define a
> constructor that takes a parameter. It only has the default
> parameterless constructor! So what is: new Tuna(*this);

Open your textbook on the chapter about constructors and read what
constructors exist even if you don't define any. Also read what other
functions exist even if you don't declare/define them. And when they
don't...

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

Mr Flibble

unread,
Apr 8, 2015, 4:53:23 PM4/8/15
to
The implicitly defined copy constructor is getting called. Also, fish
are not sausages so please adjust accordingly.

/Flibble

Doug Mika

unread,
Apr 8, 2015, 5:01:17 PM4/8/15
to
so the "new" keyword can invoke the copy constructor?

Christopher Pisz

unread,
Apr 8, 2015, 6:25:18 PM4/8/15
to
You get a default constructor, copy constructor, deconstructor if one is
not defined.

It is not the "new" keyword, but the fact that you are creating a Tuna.
You could also have created it on the stack and had the same effect,
although its lifetime would have ended when it went out of scope.

It is also unwise to implement such methods as "Clone". Silly methods
like those are often carried over from people who want to shape and mold
C++ to be like Java or wherever they came from. We don't need a clone
method, because we already have the means to make a copy...via the copy
constructor:

#include <iostream>
using namespace std;


class Fish
{
public:

// Constructor made for you, if you don't make one
Fish() {};

// Copy Constructor made for you, if you don't make one
Fish(const Fish & fish) {}

// Deconstructor made for you, if you don't make one
// Except, I don't think the default would be virtual
virtual ~Fish() {};

// Made the class abstract. Cannot instantiate a Fish anymore
virtual void Swim() = 0;
};


class Tuna : public Fish
{
public:

Tuna()
:
Fish()
{
}

Tuna(const Tuna & rhs)
:
Fish(rhs)
{
}

~Tuna()
{
}

// Implements Fish
void Swim()
{
cout << "Tuna swims fast in the sea"<< endl;
}
};


int main()
{
Tuna fishyA;
Tuna fishyB(fishyA); // I 'cloned' it or better 'copied'

Tuna * fishyC = new Tuna(fishyB);
delete fishyC;

return 0;
}


--
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
---

Mr Flibble

unread,
Apr 8, 2015, 7:13:15 PM4/8/15
to
A clone method is not silly mate. A clone method is typically used in
the context of polymorphic sausages where we don't want dependencies on
concrete sausages.

It is important to not be silly when discussing serious issues and
minimizing dependencies on concrete sausages is an important design
decision that enables, for example, unit testing and TDD.

/Flibble

Öö Tiib

unread,
Apr 8, 2015, 7:25:33 PM4/8/15
to
On Thursday, 9 April 2015 01:25:18 UTC+3, Christopher Pisz wrote:
> On 4/8/2015 4:01 PM, Doug Mika wrote:
> > On Wednesday, April 8, 2015 at 2:28:26 PM UTC-6, Doug Mika wrote:
> >> I have the following two classes:
> >>
> >> class Fish{
> >> public:
> >> virtual Fish* Clone()=0;
> >> virtual void Swim()=0;
> >> };
> >>
> >> class Tune:public Fish{
> >> public:
> >> Fish* Clone(){
> >> return new Tuna(*this);
> >> }
> >>
> >> void Swim(){
> >> cout<<"Tuna swims fast in the sea"<<endl;
> >> }
> >> };
> >>
> >> my question is, what is new Tuna(*this) when Tuna doesn't define a constructor that takes a parameter. It only has the default parameterless constructor! So what is: new Tuna(*this);
> >>
> >> Much thanks
> >> Doug
> >
> > so the "new" keyword can invoke the copy constructor?
> >
>
>
>
> You get a default constructor, copy constructor, deconstructor if one is
> not defined.

Default constructor you get only if there are no constuctors defined
whatsoever. You mean destructor or move constructor with that
"deconstructor"? Destructor will be always made implicitly.
Copy and move assignment and copy and move constructor will be made
if possible.

It is legacy from C and cause serious amount of confusion among
novices. Abstract base classes that do not declare all the five
(besides default constuctor that won't be generated) let that
legacy from C to manifest itself by casual object slicing.

To make object slicing way harder we should either make destructor
of base class that won't be instantiated as separate object either
virtual or protected. Assignments we should make deleted.
If copy and/or move is planned to be possible then we should make
according constructor protected, otherwise deleted.

> It is not the "new" keyword, but the fact that you are creating a Tuna.
> You could also have created it on the stack and had the same effect,
> although its lifetime would have ended when it went out of scope.
>
> It is also unwise to implement such methods as "Clone". Silly methods
> like those are often carried over from people who want to shape and mold
> C++ to be like Java or wherever they came from. We don't need a clone
> method, because we already have the means to make a copy...via the copy
> constructor:

It is not silly. Sometimes we need dynamic polymorphism in C++.
Often we need it for components of bigger object to be dynamically
polymorphic. Sometimes we later need a deep copy made from object that
contains dynamically polymorphic components. Lack of such 'virtual clone'
will cause that deep copy to be a big silly mess.

Christopher Pisz

unread,
Apr 8, 2015, 7:41:11 PM4/8/15
to
On 4/8/2015 6:25 PM, Öö Tiib wrote:
SNIP
> It is not silly. Sometimes we need dynamic polymorphism in C++.
> Often we need it for components of bigger object to be dynamically
> polymorphic. Sometimes we later need a deep copy made from object that
> contains dynamically polymorphic components. Lack of such 'virtual clone'
> will cause that deep copy to be a big silly mess.
>

Can you give an example of the problem? I am sure there is a better way
then defining a Clone method that returns a raw pointer.

If I've got a Fish and I want to make a copy that is a Tuna, I can't and
shouldn't be able to, until I know the Fish is a Tuna through dynamic
cast and check.

If I've got a Tuna and I want a Fish, I can copy construct another Tuna
and access everything that is part of the Fish.

Maybe I am not getting what you are driving at with the description of
"dynamically polymorphic". Google doesn't seem to know about the phrase
either, just its individual components, which I am sure we all understand.
Message has been deleted

Öö Tiib

unread,
Apr 8, 2015, 8:49:59 PM4/8/15
to
On Thursday, 9 April 2015 02:41:11 UTC+3, Christopher Pisz wrote:
> On 4/8/2015 6:25 PM, Öö Tiib wrote:
> SNIP
> > It is not silly. Sometimes we need dynamic polymorphism in C++.
> > Often we need it for components of bigger object to be dynamically
> > polymorphic. Sometimes we later need a deep copy made from object that
> > contains dynamically polymorphic components. Lack of such 'virtual clone'
> > will cause that deep copy to be a big silly mess.
> >
>
> Can you give an example of the problem?

Slicing will typically cause damaged invariant of most derived object.

struct A
{
A(int a) : a_var(a) {}
int a_var;
};

struct B : public A
{
B(int a, int b) : A(a), b_var(b) {}
int b_var;
};

B &getB()
{
static B b(1, 2);
return b;
}

int main()
{
// Assignment by value to a
A a(3);
a = getB();
// base class subobject of b is copied to a
// that may be is not what we want

B b2(3, 4);
A &a2 = b2;
a2 = getB();
// only base class subobject was assigned so
// b2.a_var == 1, b2.b_var == 4!
// that is next to never what we want

return 0;
}


> I am sure there is a better way
> then defining a Clone method that returns a raw pointer.

No. There are covariance of raw pointers but there are no
covariance of smart pointers. So returning smart pointer
would lose virtual of clone method.

> If I've got a Fish and I want to make a copy that is a Tuna, I can't and
> shouldn't be able to, until I know the Fish is a Tuna through dynamic
> cast and check.

With clone you can have pool of different fishes and still make
deep copy of it. No typeid checking or dynamic casting is needed.
The typeid checking and dynamic casting involves that designer of
pool of fishes has to have deep knowledge about all of fish types
that can be in it. It is ugly to read and error-prone if new
fish class is added. That is silly mess of design.

> If I've got a Tuna and I want a Fish, I can copy construct another Tuna
> and access everything that is part of the Fish.

The whole point of dynamic polymorphism is that you can have
a Fish (std::unique_ptr<Fish>) that may be only run-time known
if it is Tuna or Shark. It did enter the "gulf" from "sea"
and so only that 'unique_ptr' value was passed over.

> Maybe I am not getting what you are driving at with the description of
> "dynamically polymorphic". Google doesn't seem to know about the phrase
> either, just its individual components, which I am sure we all understand.

Class is dynamically polymorphic when it contains virtual functions.
Often we do not need any virtual functions but sometimes we really
do. It is typically case when we will have otherwise repetitive
table lookup, if-else and/or switch-case chain over some sort of
"kind" or "type" member value in C to differentiate between behavior.
C++ has virtual functions to make it bit less of a mess and it also
can perform better.

In some languages like Objective-C or Javascript all methods are
virtual. That is at other edge evil since it makes the things too
loose and it also hurts performance a bit when virtual is not needed.

Message has been deleted

Öö Tiib

unread,
Apr 8, 2015, 9:42:42 PM4/8/15
to
On Thursday, 9 April 2015 03:56:47 UTC+3, Stefan Ram wrote:
> Öö Tiib <oot...@hot.ee> writes:
> >Often we do not need any virtual functions but sometimes we really
> >do.
>
> »Avoid type switching; prefer polymorphism.«
>
> Herb Sutter

Often we do not need neither. Often we know full type of objects
(so any virtual is pointless).
Sometimes we need even more loose coupling. Like "task" is in
"schedule" and it is *not* business of "schedule" to care what
"task" does to what, only when to invoke it. Having some Task
base class with 'virtual void doIt()' is typically worse than
to have 'typedef std::function<void()> Task' on such case.

So virtual function can be either unneeded or too intrusive.

Chris Vine

unread,
Apr 9, 2015, 6:30:26 AM4/9/15
to
On Wed, 8 Apr 2015 17:49:47 -0700 (PDT)
Öö Tiib <oot...@hot.ee> wrote:
[snip]
> No. There are covariance of raw pointers but there are no
> covariance of smart pointers. So returning smart pointer
> would lose virtual of clone method.

Can you unpack this one for me, with an example of what you have in
mind?

std::unique_ptr and std::shared_ptr have a templated version of the
move constructor and move assignment operator and (for std::shared_ptr)
copy constructor and copy assignment operator to allow implicit
covariant casts in the same circumstances that pointer casts would be
available.

Contravariant casting using dynamic_cast is missing for smart pointers
(unless you do it by hand), but that is rarely what you want anyway.

Chris

Mr Flibble

unread,
Apr 9, 2015, 10:48:20 AM4/9/15
to
Constructors have no bearing on return type covariance as far as virtual
sausages are concerned.

/Flibble

Öö Tiib

unread,
Apr 9, 2015, 10:57:14 AM4/9/15
to
On Thursday, 9 April 2015 13:30:26 UTC+3, Chris Vine wrote:
> On Wed, 8 Apr 2015 17:49:47 -0700 (PDT)
> Öö Tiib <oot...@hot.ee> wrote:
> [snip]
> > No. There are covariance of raw pointers but there are no
> > covariance of smart pointers. So returning smart pointer
> > would lose virtual of clone method.
>
> Can you unpack this one for me, with an example of what you have in
> mind?

#include <memory>
struct A
{
// virtuals
virtual A*
clone() const { return new A(*this); };

virtual std::unique_ptr<A>
smart_clone() const { return std::unique_ptr<A>(new A(*this)); }

};

struct B : public A
{
// overrides
B*
clone() const override { return new B(*this); };
// OK

std::unique_ptr<B>
smart_clone() const override { return std::unique_ptr<B>(new B(*this)); }
// compile error
};

Raw pointers have covariance; smart pointers have no covariance in context of
virtual functions.

> std::unique_ptr and std::shared_ptr have a templated version of the
> move constructor and move assignment operator and (for std::shared_ptr)
> copy constructor and copy assignment operator to allow implicit
> covariant casts in the same circumstances that pointer casts would be
> available.

It is not enough to affect the problem I described.

I have to return 'std::unique_ptr<A>' from 'smart_clone' of B or there are
no override. However that means the 'smart_clone' is less convenient than
'clone' in situation where I need deep copy of 'std::unique_ptr<B>' and
so expect to have 'std::unique_ptr<B>' as well.

> Contravariant casting using dynamic_cast is missing for smart pointers
> (unless you do it by hand), but that is rarely what you want anyway.

I consider usage of 'dynamic_cast' only on the ultra rare cases when I need
cross casting. Otherwise I simply don't use it.

Chris Vine

unread,
Apr 9, 2015, 1:06:56 PM4/9/15
to
On Thu, 9 Apr 2015 07:56:59 -0700 (PDT)
Öö Tiib <oot...@hot.ee> wrote:
> On Thursday, 9 April 2015 13:30:26 UTC+3, Chris Vine wrote:
> > Can you unpack this one for me, with an example of what you have in
> > mind?
>
> #include <memory>
> struct A
> {
> // virtuals
> virtual A*
> clone() const { return new A(*this); };
>
> virtual std::unique_ptr<A>
> smart_clone() const { return std::unique_ptr<A>(new
> A(*this)); }
> };
>
> struct B : public A
> {
> // overrides
> B*
> clone() const override { return new B(*this); };
> // OK
>
> std::unique_ptr<B>
> smart_clone() const override { return
> std::unique_ptr<B>(new B(*this)); } // compile error
> };
>

[snip]

> I have to return 'std::unique_ptr<A>' from 'smart_clone' of B or
> there are no override. However that means the 'smart_clone' is less
> convenient than 'clone' in situation where I need deep copy of
> 'std::unique_ptr<B>' and so expect to have 'std::unique_ptr<B>' as
> well.

OK, thanks, I see the point.

Chris

Jorgen Grahn

unread,
Apr 9, 2015, 4:29:41 PM4/9/15
to
On Wed, 2015-04-08, 嘱 Tiib wrote:
> On Thursday, 9 April 2015 01:25:18 UTC+3, Christopher Pisz wrote:
>> On 4/8/2015 4:01 PM, Doug Mika wrote:
>> > On Wednesday, April 8, 2015 at 2:28:26 PM UTC-6, Doug Mika wrote:
>> >> I have the following two classes:
>> >>
>> >> class Fish{
>> >> public:
>> >> virtual Fish* Clone()=0;
>> >> virtual void Swim()=0;
>> >> };
...
>> It is also unwise to implement such methods as "Clone". Silly methods
>> like those are often carried over from people who want to shape and mold
>> C++ to be like Java or wherever they came from. We don't need a clone
>> method, because we already have the means to make a copy...via the copy
>> constructor:
>
> It is not silly. Sometimes we need dynamic polymorphism in C++.

Undoubtedly ... but the OP is obviously a newbie, and the things
you're talking about is (should be) an advanced and late topic.

I have to agree with Mr Pisz: I sense Java, or Smalltalk, or whatever,
lurking in the background here. Continuing that path is not a good
way to learn how to use C++ well.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Öö Tiib

unread,
Apr 9, 2015, 6:57:40 PM4/9/15
to
On Thursday, 9 April 2015 23:29:41 UTC+3, Jorgen Grahn wrote:
> On Wed, 2015-04-08, 嘱 Tiib wrote:
> > On Thursday, 9 April 2015 01:25:18 UTC+3, Christopher Pisz wrote:
> >> On 4/8/2015 4:01 PM, Doug Mika wrote:
> >> > On Wednesday, April 8, 2015 at 2:28:26 PM UTC-6, Doug Mika wrote:
> >> >> I have the following two classes:
> >> >>
> >> >> class Fish{
> >> >> public:
> >> >> virtual Fish* Clone()=0;
> >> >> virtual void Swim()=0;
> >> >> };
> ...
> >> It is also unwise to implement such methods as "Clone". Silly methods
> >> like those are often carried over from people who want to shape and mold
> >> C++ to be like Java or wherever they came from. We don't need a clone
> >> method, because we already have the means to make a copy...via the copy
> >> constructor:
> >
> > It is not silly. Sometimes we need dynamic polymorphism in C++.
>
> Undoubtedly ... but the OP is obviously a newbie, and the things
> you're talking about is (should be) an advanced and late topic.

It should be advised that if there is hierarchy with virtual
functions and if objects in such have to be copied at all
then 'clone' is idiomatically the best of choices.

> I have to agree with Mr Pisz: I sense Java, or Smalltalk, or whatever,
> lurking in the background here. Continuing that path is not a good
> way to learn how to use C++ well.

Programmer has to have experience of debugging deep class hierarchy with
full yo yo of virtuals to realize how *not* to use C++ well. People
learn fastest from their own mistakes. Usage of other ways but
'clone' is one certain source of those headaches.

Jorgen Grahn

unread,
Apr 11, 2015, 11:43:38 AM4/11/15
to
On Thu, 2015-04-09, 嘱 Tiib wrote:
> On Thursday, 9 April 2015 23:29:41 UTC+3, Jorgen Grahn wrote:
Ah, I see it now: he was critizising the clone(), not the
virtual-ness. You're probably right, then. (I have to admit I use
inheritance so rarely that I never had to fight slicing.)
0 new messages