Polymorphism C++ Copy Constructor Vs Assignment

Brian R. Bondy wrote:


One last step to tie it all together, RTTI:

You can use RTTI to properly handle virtual functions that take in your type. Here is the last piece of the puzzle to figure out how to properly handle assignment when dealing with possibly inherited types.

I would like to add to this solution a few remarks. Having the assignment operator declared the same as above has three issues.

The compiler generates an assignment operator that takes a const D& argument which is not virtual and does not do what you may think it does.

Second issue is the return type, you are returning a base reference to a derived instance. Probably not much of an issue as the code works anyway. Still it is better to return references accordingly.

Third issue, derived type assignment operator does not call base class assignment operator (what if there are private fields that you would like to copy?), declaring the assignment operator as virtual will not make the compiler generate one for you. This is rather a side effect of not having at least two overloads of the assignment operator to get the wanted result.

Considering the base class (same as the one from the post I quoted):

The following code completes the RTTI solution that I quoted:

This may seem a complete solution, it's not. This is not a complete solution because when you derive from D you will need 1 operator = that takes const B&, 1 operator = that takes const D& and one operator that takes const D2&. The conclusion is obvious, the number of operator =() overloads is equivalent with the number of super classes + 1.

Considering that D2 inherits D, let's take a look at how the two inherited operator =() methods look like.

It is obvious that the operator =(const D2&) just copies fields, imagine as if it was there. We can notice a pattern in the inherited operator =() overloads. Sadly we cannot define virtual template methods that will take care of this pattern, we need to copy and paste multiple times the same code in order to get a full polymorphic assignment operator, the only solution I see. Also applies to other binary operators.


Edit

As mentioned in the comments, the least that can be done to make life easier is to define the top-most superclass assignment operator =(), and call it from all other superclass operator =() methods. Also when copying fields a _copy method can be defined.

There is no need for a set defaults method because it would receive only one call (in the base operator =() overload). Changes when copying fields are done in one place and all operator =() overloads are affected and carry their intended purpose.

Thanks sehe for the suggestion.

Copy constructor for derived class

I'm just wondering how to write the copy constructor, along with the operator =, for a derive class, properly.



So - first of all, is this a standard way of doing copy constructors / operator =? I know these are very simple classes, but if i can understand these properly, then i can understand more complex ones.

In the derived copy constructor, i have called the base copy constructor - so should this then set the base member variables correctly? Or should i set everything in the derived operator =?

I want to make sure everything is copied correctly, but i also want to understand that what i've done is correct. Of course i could simply set all the base memeber variables in the derived operator =....... that way i'd be sure.
You haven't defined a copy-constructor (you think you have, but you haven't) so the compiler will make its own. In actual fact, the only constructor you've overloaded is the default one.

To properly overload the copy-constructor, the parameter list must have only 1 parameter, and that's a reference to a constant class . For instance:


When dealing with inheritance, be sure to invoke the base-copy-constructor, because otherwise, the base will not be affected. Though, it seems you've already done this.

Secondly, you've not overloaded the assignment operator properly, either. Again, the compiler will provide its own assignment operator. Like the copy-constructor, at least 1 overload of the assignment operator must take a reference to a constant class .

Wazzak
It is better when the copy constructor (and the copy assignment operator) accepts a constant reference to an object of its class.

Consider your declaration



and the following code



In the both cases of declarations of b2 and b3 a compilation error will be issued (provided that the compiler does not have a bug:) ).
In the first case when b2 is defined your copy constructor may not be called because object b1 is const and only a const reference can be specified for it.
In the second case the call Base() creates a temporary unnamed object. Such an object also may be binded only with a const reference.

The same remarks are valid for the copy assignment operator that is it shall have as the parameter a const reference to an object of its class.

And you do not need call the base copy constructor as you are doing

Derived::Derived(Derived &other)
:Base(other) // <---- do we do it like this?


It will be called implicitly by the derived copy constructor.

@Framework (2487)

You haven't defined a copy-constructor (you think you have, but you haven't) so the compiler will make its own. In actual fact, the only constructor you've overloaded is the default one.



You are wrong. This

// copy constructor
Base::Base(Base &other)
{
*this = other;
}


is a copy constructor. The compiler will not create its own copy constructor.
It's not a copy-constructor, but if you want to provide false information, I won't allow you. The compiler will generate its own copy-constructor, but only if it's required.

Wazzak
@Framework (2489)

It's not a copy-constructor, but if you want to provide false information, I won't allow you. The compiler will generate its own copy-constructor, but only if it's required.


I already gave your a good advice: read the C++ standard! It is very useful!
That you will understand that you are wrong consider the example I already showed here.



As you affirm in this case the compiler will create a copy constructor will not it? However if you run this code provided that you have the constructor



the compiler will issue an error because none copy constructor it did create. It already have the user defined copy constructor.
Fine, go ahead and post false information - I'm sick of arguing with you.

Wazzak
Till now it is you who give the false information. Did you try the example I showed? And where is your copy constructor created by the compiler?! Why the compiler does issue an error?
I did not get your answer except only your emotions which based on your lack of knowledge of the C++ standard.

Any constructor which has as the parameter a reference to an object of its type, a const reference to an object of its type, a volatile reference to an object of its type or a const volatile reference to an object of its type all these are copy constructors. If at least one copy constructor is declared by the user when the compiler will not generate its own copy constructor. The user can declare all four kinds of the copy constructor.

Even the following declaration



is a copy constructor.
I'm afraid vlad is correct about it being a copy-constructor.
§12.8/2
A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other parameters have default arguments (8.3.6). [ Example: X::X(const X&) and X::X(X&,int=1) are copy constructors.


vlad from moscow wrote:
you do not need call the base copy constructor as you are doing
It will be called implicitly by the derived copy constructor.

This is not correct though. GCC even generates a warning if I try to remove :
warning: base class 'class Base' should be explicitly initialized in the copy constructor [-Wextra]


In Derived::operator= the variables in Base is currently not set. You can call Base::operator= from Derived::operator= to set them
@Peter87
This is not correct though. GCC even generates a warning if I try to remove :Base(other):


warning: base class 'class Base' should be explicitly initialized in the copy constructor [-Wextra]


Now you are wrong. Objects are created by first implicitly calling a base copy consttructor and only then by calling the most derived copy constructor.
Do not trust the compiler. All compilers contain bugs!:)

I think that maybe the warning message was generated by the copy assignment operator that is used inside the body of the copy constructor. So do not be hurry.:) But in any case there is no problem that the base copy constructor was not specified in the mem initializing list. I is not required.
vlad, do you even know why the copy-constructor requires a constant reference? It's because of the following:

- It allows constant class objects to be passed
- It allows temporary objects to be passed
- It guarantees referent protection

By omitting from the copy-constructor declaration, the following code is erroneous:


You cannot pass constant objects, and you cannot bind temporaries to the parameter. This is the same for the assignment operator. By default, the compiler will generate a copy-constructor that takes a reference to a constant class ; just like the assignment operator. Why? Because it's the better declaration.

vlad from moscow wrote:
"Do not trust the compiler."

Now who's wrong.

By the way, I know what a valid copy-constructor looks like; I was suggesting the best one.

Wazzak
@Framework
vlad, do you even know why the copy-constructor requires a constant reference? It's because of the following:

- It allows constant class objects to be passed
- It allows temporary objects to be passed
- It guarantees referent protection



I do not understand why are you writing this because 1) we were talking about what is a copy constructor 2) in my first message I pointed out that it is better to declare the copy constructor with a const reference and demonstrated this with examples.
So you are arguing with yourself.:) Maybe it is very useful business to argue with yourself?

@Framework
You cannot pass temporaries, you cannot pass constant objects, and you cannot bind temporaries to the parameter.


And I do not understand why are you repeating these after me?!!! See again my first message and reread your messages where you stated 1) that the compiler generates its own copy constructor in spite of presence of a user copy constructor 2) that I give a false information.
I am sorry but it seems that you are dishonest man.


Shall I repeat your statements as for example

@Framework
It's not a copy-constructor, but if you want to provide false information, I won't allow you. The compiler will generate its own copy-constructor, but only if it's required.


or you will understand at last that you was wrong?



Let's review your first post:

1)

vlad from moscow wrote:
vlad from moscow wrote:
"In the second case the call Base() creates a temporary unnamed object."

This isn't an error, nor does it create a temporary object; it's a function prototype.

2)

vlad from moscow wrote:

"It will be called implicitly by the derived copy constructor."

This is false; The compiler will not implicitly invoke the copy-constructor of the base-class, because the copy-constructor of the base class requires an argument.

vlad from moscow wrote:
"or you will understand at last that you was wrong? "

I was 100% right about what I said about the constructor being defined only if it's needed; I was not wrong. I'll explain it again, just for you: A compiler will only generate a copy-assignment operator, copy-constructor, and destructor only if they are not overloaded, and only if they are required.

Wazzak
Wow, that was a heated argument..

Anyway, back to the original post, the problem it has is that the copy constructor (which should be taking ref to const, to be more useful), is defined in terms of the copy assignment operator. It should have been written this way:



Also, the derived operator= forgets to copy the inherited members a and b.

Of course, all this could simply be omitted, since the implicitly-defined copy ctor and assignment would do the right thing in this case.
Framework wrote:
it's a function prototype
¿? No, it is not.
It is an object definition.

Framework wrote:
The compiler will not implicitly invoke the copy-constructor of the base-class, because the copy-constructor of the base class requires an argument.
That.
If you put nothing, then the default constructor will be called.

Just to state it:
is a copy constructor, but you should prefer
ne555 wrote:
"It is an object definition."

Compile this:



ne555 wrote:
"If you put nothing, then the default constructor will be called."

That's the problem; you want the base class' copy-constructor to be called when you invoke the copy-constructor of the derived class. If you don't, the base members will be initialised to default values, and will not be initialised based on the state of the referent's base-class.

Wazzak
Interesting... I was expecting an asterisk somewhere.
ne555 wrote:
"Interesting... I was expecting an asterisk somewhere."

This:


...is equivalent to:


Wazzak

@Framework

Let's review your first post:

1)

vlad from moscow wrote:

Base b2( Base() ); // compilation error

vlad from moscow wrote:

"In the second case the call Base() creates a temporary unnamed object."

This isn't an error, nor does it create a temporary object; it's a function prototype.



You do not know 1) what is the copy constructor;
you do niot know 2) when the compiler declares implicitly the copy constructor;
you do not know 3) what is the copy assignment operator;
you do not know 4) when the compiler declares implicitly the copy assignment operator;
you do not know 5) that standard class std::auto_ptr uses the copy constructor and the copy assignment operator which use as the parameter non-const reference to an object of its type;


And these are not only my words. You demonstrated these yourself.

If I made an error somewhere then I am ready to admit it. But I never say when I do not know something that my opponent are saying false and I never start tell llies. The same I can not say about you.

@ne555
Framework wrote:

Base b2( Base() ); it's a function prototype

¿? No, it is not.
It is an object definition.



It is not a problem. We very often forgot that the constructor is not a function. It is a special syntax and Base() is a type-id. This is in fact a typo. It is enough to substitute the constructor for any function that returns an object by value. For example


and to write



Topic archived. No new replies allowed.

0 thoughts on “Polymorphism C++ Copy Constructor Vs Assignment”

    -->

Leave a Comment

Your email address will not be published. Required fields are marked *