2.2. Constructors#

In the previous section, we learned about classes and how to define them. We saw private and public members, and the need for getter and setter functions to access and modify private members. In this section, we will learn about constructors, which are special member functions of a class that are called when an object of the class is instantiated. Constructors are used to initialize the members of a class when an object is created.

2.2.1. Default Constructor#

Recall the example of the Student class, we used in the previous section.

Code in Student.h

#include <string>
using namespace std;

class Student {
 private:
  string name;
  int ID;

 public:
  void print();
  void setName(string name);
  string getName();
};

Code in Student.cpp

#include <iostream>
#include "Student.h"
using namespace std;

void Student::print() {
  cout << "Name: " << name << endl << "ID: " << ID << endl;
}

void Student::setName(string n) {
  name = n;
}

string Student::getName() {
  return name;
}

Code in main.cpp

 1#include <iostream>
 2#include "Student.h"
 3using namespace std;
 4
 5int main(void) {
 6  Student x;
 7
 8  x.setName("Cindy");
 9  cout << x.getName() << endl;
10
11  x.print(); // ID is not initialized
12  return 0;
13}

Problem! As we create the object x, the value of name and ID are uninitialized. It is a good practice to initialize value of variables as we declare them to avoid having undefined behavior resulting from uninitialized variables. For example, in line 11, the output of the program is undefined as the value of ID is not initialized.

Solution! To initialize the members of a class when an object is created, we can use a constructor. A constructor is a special member function of a class that is given by default when a class is defined. It is called automatically when an object is created. By default, the constructor is an empty function that does nothing. This is called a default constructor. We can define our own constructor to initialize the members of a class when an object is created.

The constructor has

  • the same name as the class

  • no return type (not even void)

  • called when an object is created, but never called explicitly

  • must be a public member

Let’s define a constructor for the Student class to initialize the name and ID members.

Code in Student.h

 1#include <string>
 2using namespace std;
 3
 4class Student {
 5 private:
 6  string name;
 7  int ID;
 8
 9 public:
10  Student(); // Constructor
11  void print();
12  void setName(string name);
13  string getName();
14};

In Student.h file, in line 10, we add the constructor declaration to the Student class. The constructor is a function with the same name as the class and no return type.

Code in Student.cpp

 1#include <iostream>
 2#include "Student.h"
 3using namespace std;
 4
 5Student::Student() {
 6  ID = 0;
 7  name = "no name";
 8}
 9
10void Student::print() {
11  cout << "Name: " << name << endl << "ID: " << ID << endl;
12}
13
14void Student::setName(string n) {
15  name = n;
16}
17
18string Student::getName() {
19  return name;
20}

In Student.cpp file, we add the constructor implementation for the Student class. No return type is specified for the constructor. We are setting the value of ID to 0 and name to "no name" in the default constructor.

Code in main.cpp

 1#include <iostream>
 2#include "Student.h"
 3using namespace std;
 4
 5int main(void) {
 6  Student x;  // Constructor is called
 7
 8  x.print();
 9  return 0;
10}

Output

Name: no name
ID: 0

In main.cpp file, we create an object x of the Student class. The constructor is called automatically when the object is created. The value of name and ID are initialized to "no name" and 0, respectively. The output of the program is now defined.

Student y[10]; creates an array of 10 Student objects. The constructor is called for each object in the array, i.e., the constructor is called 10 times.

Student *z; creates a pointer z to a Student object. The pointer is not initialized and has a garbage address. The constructor is not called as no object is created. The constructor is called when an object is created, not when a pointer is created.

2.2.2. Other Constructors#

As we have seen, the default constructor has no parameters passed to it. What if we want to initialize the members of a class with some values when an object is created? We can define our own constructor with parameters. These are called parameterized constructors.

Code in Student.h

 1#include <string>
 2using namespace std;
 3
 4class Student {
 5 private:
 6  string name;
 7  int ID;
 8
 9 public:
10  Student();                  // Default constructor
11  Student(int id);            // 1st constructor
12  Student(int id, string n);  // 2nd constructor
13  void print();
14  void setName(string name);
15  string getName();
16};

In Student.h file, we add two more constructors to the Student class. The first constructor in line 7 takes an integer parameter id and initializes the ID member with the value of id, and sets the name member to "no name".

The second constructor in line 8 takes an integer parameter id and a string parameter n and initializes the ID and name members with the values of id and n, respectively.

Code in Student.cpp

 1#include "Student.h"
 2#include <iostream>
 3using namespace std;
 4
 5Student::Student() {
 6  ID = 0;
 7  name = "no name";
 8}
 9
10Student::Student(int id) {
11  ID = id;
12  name = "no name";
13}
14
15Student::Student(int id, string n) {
16  ID = id;
17  name = n;
18}
19
20void Student::print() {
21  cout << "Name: " << name << endl << "ID: " << ID << endl;
22}
23
24void Student::setName(string n) {
25  name = n;
26}
27
28string Student::getName() {
29  return name;
30}

In Student.cpp file, we add the implementation for the two new constructors. The first constructor in lines 10-13 initializes the ID member with the value of id and sets the name member to "no name".

The second constructor in lines 15-18 initializes the ID and name members with the values of id and n, respectively.

Code in main.cpp

 1#include <iostream>
 2#include "Student.h"
 3using namespace std;
 4
 5int main(void) {
 6  Student x;                   // Default constructor is called
 7  Student y(20207);            // 1st constructor is called
 8  Student z(20207, "Osiris");  // 2nd constructor is called
 9  cout << "Student x" << endl;
10  x.print();
11  cout << "Student y" << endl;
12  y.print();
13  cout << "Student z" << endl;
14  z.print();
15  return 0;
16}

Output

Student x:
Name: no name
ID: 0
Student y:
Name: no name
ID: 20207
Student z:
Name: Osiris
ID: 20207

In the main function, we create three objects x, y, and z of the Student class. The default constructor is called for object x, the first constructor is called for object y, and the second constructor is called for object z. The value of name and ID members are initialized accordingly as shown in the output.

How is it possible to have multiple constructors with same name but different number of parameters?

The constructors are distinguished by the number of parameters passed to them. The compiler determines which constructor to call based on the number of parameters passed to it. Defining multiple constructors with the same name but different number of parameters is called function overloading. This is used for other functions as well, not just constructors.

Important!

If the default constructor is not defined, the compiler will provide one.

However, if any constructor is defined, for example, the first constructor in the example above, the compiler will not provide the default constructor. In that case, for example, Student x; will result in a compilation error as the default constructor Student::Student() is not defined.