Copy constructor for derived class

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80


// base class 
class Base
{
  public:

   int a;
   double b;

   Base(int a1=0, double b1=0);
   Base(Base &other);  // copy constructor

   Base& operator = (Base &other);
};

// constructor method
Base::Base(int a1, double b1)
{
  a = a1;
  b = b1;
}

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

// operator equals
Base& Base::operator = (Base &other)
{
  a = other.a;
  b = other.b;

  return *this;
}


// -----------------------------------------
// -----------------------------------------

// now the derived class
class Derived : public Base
{
  public:

   int c;
   double d;

   Derived(int a1=0, double b1=0, int c1=0, double d1=0);
   Derived(Derived &other); // copy constructor

   Derived& operator = (Derived &other); 
};

// derived methods
Derived::Derived(int a1, double b1, int c1, double d1)
        :Base(a1, b1)
{
  c = c1;
  d = d1;
}

// derived copy constructor
Derived::Derived(Derived &other)
        :Base(other)   // <---- do we do it like this? 
{
  *this = other;
}

// derived operator =
Derived& Derived::operator = (Derived &other)
{
  c = other.c;
  d = other.d;

  return *this;
}


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.
closed account (zb0S216C)
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 X. For instance:

1
2
3
4
5
6
class some_class
{
    public:
        some_class(some_class const &instance_); // Copy-constructor
        some_class(some_class &instance_); // Default constructor
};

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

Wazzak
Last edited on
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

Base(Base &other);


and the following code

1
2
3
const Base b1;
Base b2( b1 );         // compilation error
Base b2( Base() );   // compilation error 


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.
Last edited on

@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.
closed account (zb0S216C)
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.

1
2
const Base b1;
Base b2( b1 );


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

1
2
3
4
5
// copy constructor
 Base::Base(Base &other)
 {
 *this = other;
 } 


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

Wazzak
Last edited on
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

Base( Base &, int x = 10 );

is a copy constructor.
Last edited on
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
1
2
Derived::Derived(Derived &other)
:Base(other) // <---- do we do it like this? 
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 :Base(other):
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
1
2
3
4
5
6
7
8
Derived& Derived::operator = (Derived &other)
{
	Base::operator=(other);
	c = other.c;
	d = other.d;

	return *this;
}
@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.
Last edited on
closed account (zb0S216C)
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 const from the copy-constructor declaration, the following code is erroneous:

1
2
3
4
5
6
7
8
9
10
11
12
13
class some_class
{
    public:
        some_class(some_class &instance_) { }
        some_class() { }
};

int main()
{
    some_class const a_;
    some_class b_(a_); // Error
    some_class c_((some_class())); // Error
}

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 X; 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
Last edited on
@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?



Last edited on
closed account (zb0S216C)
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.

2)

vlad from moscow wrote:
1
2
Derived::Derived(Derived &other)
:Base(other) // <---- do we do it like this? 

"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
Last edited on
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:

1
2
3
Derived::Derived(const Derived& other)
    : Base(other), c(other.c), d(other.d)
{} 


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:
Base b2( Base() ); 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:
foo(foo&); is a copy constructor, but you should prefer
foo(const foo&);
closed account (zb0S216C)
ne555 wrote:
"It is an object definition."

Compile this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class some_class
{
    public:
        some_class() { }
        some_class(some_class const &instance_) { }
};

int main()
{
    some_class c_((some_class())); // Object definition.
    some_class a_(some_class());   // Prototype.
    some_class b_;

    a_(); // Error, too few arguments/undefined reference.

// a_ is a function than takes a pointer to a function that
// takes no arguments, and returns a some_class object.
// a_ also returns a some_class object.
}


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
Last edited on
Interesting... I was expecting an asterisk somewhere.
closed account (zb0S216C)
ne555 wrote:
"Interesting... I was expecting an asterisk somewhere."

This:

 
some_class a_(some_class());

...is equivalent to:

 
some_class a_(some_class(*)());

Wazzak
Last edited on

@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.
Last edited on

@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

Base f() { return ( Base() ); }
and to write

Base b2( f() );

Topic archived. No new replies allowed.