class Z { public: Z(void); ~Z(void); }; Z::Z(void) { cout << "in Z::Z(void)" << endl; } Z::~Z(void) { cout << "in Z::~Z(void)" << endl; } class Y { Z *pZ; public: Y(void); ~Y(void); }; Y::Y(void) { cout << "in Y::Y(void)" << endl; pZ = new Z; } Y::~Y(void) { cout << "in Y::~Y(void)" << endl; delete pZ; } class X { Y *pY; public: X(void); ~X(void); }; X::X(void) { cout << "in X::X(void)" << endl; pY = new Y; } X::~X(void) { cout << "in X::~X(void)" << endl; delete pY; }
In this definition, an object of class X
has a pointer to
an object of class Y
. An object of class Y
has a pointer
to point to an object of class Z
. What is important here is that
when an X
object is created, it also creates an Y
object dynamically. When the Y
object is being created, it
also creates a Z
object.
Note that the creations of the Y
object and the Z
object
are implicit. In other words, the following code creates a Y
and a Z
without any explicit code:
X myX;
In fact, observe the behavior of the following code:
{ X *myX; myX = new X; cout << "in the block" << endl; delete myX; }
Here is the sequence:
X
X::X
is invoked
Y
Y::Y
is invoked
Z
Z::Z
is invoked and completes
Z
object is reserved and initialized
Z
object is stored in pZ
of
the Y
object
Y::Y
completes
Y
object is fully initialized
Y
object is stored in pY
of
the X
object
X::X
completes
X
object is fully initialized
X
object is stored in myX
new
statement executes
delete myX
X::~X
is invoked, it calls
delete pY
Y::~Y
is invoked, it calls
delete pZ
Z::~Z
is invoked and completed
Z
object is freed
Y::~Y
completes
Y
object is freed
X::~X
completes
X
object is freed