I know that the compiler sometimes provides a default copy constructor if you don't implement yourself. I am confused about what exactly this constructor does. If I have a class that contains other objects, none of which have a declared copy constructor, what will the behavior be? For example, a class like this:
class Foo {
Bar bar;
};
class Bar {
int i;
Baz baz;
};
class Baz {
int j;
};
Now if I do this:
Foo f1;
Foo f2(f1);
What will the default copy constructor do? Will the compiler-generated copy constructor in Foo
call the compiler-generated constructor in Bar
to copy over bar
, which will then call the compiler-generated copy constructor in Baz
?
Foo f1;
Foo f2(f1);
Yes this will do what you expect it to:
The f2 copy constructor Foo::Foo(Foo const&) is called.
This copy constructs its base class and then each member (recursively)
If you define a class like this:
class X: public Y
{
private:
int m_a;
char* m_b;
Z m_c;
};
The following methods will be defined by your compiler.
There are actually two default constructors.
One is used for zero-initialization
while the other is used for value-initialization
. The used depends on whether you use ()
during initialization or not.
// Zero-Initialization compiler generated constructor
X::X()
:Y() // Calls the base constructor
// If this is compiler generated use
// the `Zero-Initialization version'
,m_a(0) // Default construction of basic PODS zeros them
,m_b(0) //
m_c() // Calls the default constructor of Z
// If this is compiler generated use
// the `Zero-Initialization version'
{
}
// Value-Initialization compiler generated constructor
X::X()
:Y() // Calls the base constructor
// If this is compiler generated use
// the `Value-Initialization version'
//,m_a() // Default construction of basic PODS does nothing
//,m_b() // The values are un-initialized.
m_c() // Calls the default constructor of Z
// If this is compiler generated use
// the `Value-Initialization version'
{
}
Notes: If the base class or any members do not have a valid visible default constructor then the default constructor can not be generated. This is not an error unless your code tries to use the default constructor (then only a compile time error).
X::X(X const& copy)
:Y(copy) // Calls the base copy constructor
,m_a(copy.m_a) // Calls each members copy constructor
,m_b(copy.m_b)
,m_c(copy.m_c)
{}
Notes: If the base class or any members do not have a valid visible copy constructor then the copy constructor can not be generated. This is not an error unless your code tries to use the copy constructor (then only a compile time error).
X& operator=(X const& copy)
{
Y::operator=(copy); // Calls the base assignment operator
m_a = copy.m_a; // Calls each members assignment operator
m_b = copy.m_b;
m_c = copy.m_c;
return *this;
}
Notes: If the base class or any members do not have a valid viable assignment operator then the assignment operator can not be generated. This is not an error unless your code tries to use the assignment operator (then only a compile time error).
X::~X()
{
// First runs the destructor code
}
// This is psudo code.
// But the equiv of this code happens in every destructor
m_c.~Z(); // Calls the destructor for each member
// m_b // PODs and pointers destructors do nothing
// m_a
~Y(); // Call the base class destructor
Looking at your code the following copy constructors are generated:
Foo::Foo(Foo const& copy)
:bar(copy.bar)
{}
Bar::Bar(Bar const& copy)
:i(copy.i)
,baz(copy.baz)
{}
Baz::Baz(Baz const& copy)
:j(copy.j)
{}