Reputation: 3147
There is something that I am not able to understand. Look at this kind of main:
class C {
public:
C() { cout << "C0 "; }
C(const C&) { cout << "Cc"; }
};
class D {
public:
C c;
D() { cout << "D0 "; }
D(const D&) { cout << "Dd"; }
};
int main() {
D x; cout << endl;
D y(x); cout << endl;
return 0;
}
//output is:
C0 D0
C0 Dd
I agree on the fact that D x
gives C0 D0
as output because in class D there is a call to the default constructor of C
and then the object D
is created.
Also D y(x)
is like D y = x
where (like before) C is created (so output C0) and the the copy constructor is called. Why doesn't the Cc
appear? If you consider this code:
class C {
public:
C() { cout << "C0 "; }
C(const C&) { cout << "Cc"; }
};
class D {
public:
C c;
D() { cout << "D0 "; }
};
int main() {
D x; cout << endl;
D y(x); cout << endl;
return 0;
}
//output is:
C0 D0
Cc
Why now the output is Cc
?
The code are equal except for the fact that there isn't a definition of the copy constructor on D. Saying that D y(x)
is like D y = x
I'd expect like before that C is created (calling default constructor so output C0
) and then no text because D(const D&)
is not defined.
Maybe I am misunderstanding copy constructors. How are they called in this case?
Upvotes: 2
Views: 869
Reputation: 2106
In the first case your D Copy constructor needs to explicitly call the C copy constructor.
D(const D &d) : c(d.c)
{ cout << "Dd"; }
In the 2nd case, since you do not define a D copy-ctor, the compiler generates one for you.
To make this clearer, add an extra int to both C and D.
static int counter;
class C {
public:
int index;
C() { index = ++counter; cout << "C0 "; }
C(const C&) { index = c.counter; cout << "Cc"; }
};
class D {
public:
int dcounter;
C c;
D() { dcounter = ++counter; cout << "D0 "; }
D(const D&) : dcounter(D.dcounter)
{ cout << "Dd"; }
};
Now, step thru with a debugger, or add more printfs(). When you do D y(x), you will see that the member c in y isn't copied from anything - just constructed.
Upvotes: 6
Reputation: 598434
Also
D y(x)
is likeD y = x
It is not LIKE it, it IS EXACTLY it. The latter is just syntax sugar for the first.
where (like before)
C
is created (so outputC0
) and the the copy constructor is called
No, the C
copy constructor is not called in that case. You did not define your D
copy constructor to call the C
copy constructor, so the c
member is default-constructed instead, which is why you see C0
, but since you did not actually copy c
, you don't see Cc
.
You are expecting the D
copy constructor to automatically call the copy constructors of D
's members, but that is simply NOT the case. You have to explicitly define that behavior yourself, eg:
D(const D &src) : c(src.c) { }
Why doesn't the
Cc
appear?
Because your C
copy constructor is not called at all in your D y(x)
example.
Upvotes: 3
Reputation: 28332
When you define a custom copy constructor, it does what you tell it to; you don't tell it to copy the c
member, so it doesn't, hence C0
. Indeed, if you were to a value in that c
you'd see it's not even available in the newly copied member.
When you don't have a custom copy constructor, the default one that gets invoked invokes copy constructors for members it copies. In this case, you would see a value end up in the copied instance.
Upvotes: 3