1 Nikosida

C++ Copy Assignment Operator Of Base Class Undefined

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.

This isn't actually an answer, but the how-to question has been answered. This is the why-not.

Classes should mean something. There should be useful things you can say about any well-formed object in the class ("class invariants"), because that way you can reason about programs on the basis of how a class works. If a class is just a collection of data members, you can't do that, and have to reason about the program on the basis of each individual data element.

The proposed assignment operator will change every data member in the base class, but won't touch the ones defined in the child class. This means one of two things.

If a Child object is well-formed after another Base object is dumped into its Base component, it means that the additional data members have no real connection with the the Base data members. In that case, Child isn't really a subtype of Base, and public inheritance is the wrong relation. Child isn't in a "is-a" relation to Base, but rather a "has-a" relation. This is usually expressed by composition (Child has a Base data member), and can also be expressed by private inheritance.

If a Child object is not well-formed after another Base object is dumped into its Base component, the proposed assignment operator is a really fast and convenient method to mess up a variable.

For an example, let's have a Mammal base class and two child classes, Cetacean and Bat. Animal has things like size and weight, and the child classes have fields related to what they eat and how they move. We assign a Cetacean to a Mammal, which is reasonable (all Cetacean-specific fields are just dropped), and now we assign that Mammal to a Bat. Suddenly, we've got an twenty-ton bat.

With a well-designed set of classes, the only way I can conceive of this assignment operator even being thought of is if the child classes have no additional data members, only additional behavior, and even then it's suspect.

Therefore, my only advice is to redo your class design. Many people, particularly those familiar with Java and other languages that tend to deep inheritance hierarchies, use inheritance far too much in C++. C++ generally works best with a large number of base classes and a relatively shallow hierarchy.

Leave a Comment

(0 Comments)

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