Constructors and Destructors in C++

The constructor of a derived class first calls its base class’s constructor before it executes its own code. The destructor of a derived class executes its own code then automatically calls its base class’s destructor.

A derived class inherits accessible data fields and functions from its base class. Does it inherit constructors or destructors? Can base class constructors and destructors be invoked from derived classes? We now consider these questions and their ramifications.

1. Calling Base Class Constructors

A constructor is used to construct an instance of a class. Unlike data fields and functions, the constructors of a base class are not inherited in the derived class. They can only be invoked from the constructors of the derived classes to initialize the data fields in the base class. You can invoke the base class’s constructor from the constructor initializer list of the derived class. The syntax is as follows:

DerivedClass(parameterList): BaseC1ass()

{

// Perform initialization

}

or

DerivedClass(parameterList): BaseClass(argumentList)

{

// Perform initialization

}

The former invokes the no-arg constructor of its base class, and the latter invokes the base class constructor with the specified arguments.

A constructor in a derived class always invokes a constructor in its base class explicitly or implicitly. If a base constructor is not invoked explicitly, the base class’s no-arg constructor is invoked by default. For example,

The Circle(double radius, const string& color, bool filled) constructor (lines 17-22) in Listing 15.4, DerivedCircle.cpp, can also be implemented by invoking the base class’s constructor GeometricObject(const string& color, bool filled) as follows:

1 // Construct a circle object with specified radius, color and filled
2 Circle::Circle(double radius, const string& color, bool filled)
3 : GeometricObject(color, filled)
4 {
5    setRadius(radius);
6 }

or

1 // Construct a circle object with specified radius, color and filled
2 Circle::Circle(double radius, const string& color, bool filled)
3 : GeometricObject(color, filled), radius(radius)
4 {
5 }

The latter also initializes the data field radius in the constructor initializer. radius is a data field defined in the Circle class.

2. Constructor and Destructor Chaining

Constructing an instance of a class invokes the constructors of all the base classes along the inheritance chain. When constructing an object of a derived class, the derived class construc­tor first invokes its base class constructor before performing its own tasks. If a base class is derived from another class, the base class constructor invokes its parent class constructor before performing its own tasks. This process continues until the last constructor along the inheritance hierarchy is called. This is called constructor chaining. Conversely, the destructors are automatically invoked in reverse order. When an object of a derived class is destroyed, the derived class destructor is called. After it finishes its tasks, it invokes its base class destructor. This process continues until the last destructor along the inheritance hierarchy is called. This is called destructor chaining.

Consider the following code in Listing 15.8:

Listing 15.8 ConstructorDestructorCallDemo.cpp

1 #include <iostream>
2
using namespace std;
3
4
class Person
5 {
6     
public:
7     Person()
8     {
9        cout <<
“Performs tasks for Person’s constructor” << endl;
10    }
11
12    ~Person()
13    {
14       cout <<
“Performs tasks for Person’s destructor” << endl;
15    }
16 };
17
18
class Employee: public Person

19 {
20     
public:
21    Employee()
22    {
23       cout <<
“Performs tasks for Employee’s constructor” << endl;
24    }
25
26   ~Employee()
27    {
28       cout <<
“Performs tasks for Employee’s destructor” << endl;
29    }
30 };
31
32
class Faculty: public Employee
33 {
34     
public:
35     Faculty()
36     {
37        cout <<
“Performs tasks for Faculty’s constructor” << endl;
38     }
39
40     ~Faculty()
41     {
42        cout <<
“Performs tasks for Faculty’s destructor” << endl;
43     }
44 };
45
46
int main()
47 {
48    Faculty faculty;
49
50   
return 0;
51 }

The program creates an instance of Faculty in line 48. Since Faculty is derived from Employee and Employee is derived from Person, Faculty’s constructor invokes Employee’s constructor before it performs its own task. Employee’s constructor invokes Person’s constructor before it performs its own task, as shown in the following figure:

When the program exits, the Faculty object is destroyed. So the Faculty’s destructor is called, then Employee’s, and finally Person’s, as shown in the following figure:

Source: Liang Y. Daniel (2013), Introduction to programming with C++, Pearson; 3rd edition.

Leave a Reply

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