A constructor is a special non-static class member function that is used to initialize objects of its class type.
Example:
#include <iostream>
class Example
{
private:
int x, y;
public:
Example()
{
std::cout << "Example Constructor Initialized" << std::endl;
}
~Example()
{
std::cout << "Example Destructor Initialized" << std::endl;
}
};
int main()
{
Example e;
}
The above is an example for a basic C++ constructor and destructor.
Now, let’s look at the problem:
Problem Statement
The Example class has two private data members (x and y).
Let’s create a member function in the example class to print the values of the variables x and y.
#include <iostream>
class Example
{
private:
int x, y;
public:
Example()
{
std::cout << "Example Constructor Initialized" << std::endl;
}
~Example()
{
std::cout << "Example Destructor Initialized" << std::endl;
}
void Print()
{
std::cout << "X: " << x << std::endl
<< "Y: " << y << std::endl;
}
};
int main()
{
Example e;
e.Print();
}
Output:
Example Constructor Initialized
X: 30
Y: 0
Example Destructor Initialized
The issue with the output is that we have never initialized the x and y variable of the Example class, so when we access it, we get garbage value.
In order to solve this problem, when creating a class object, class data members can be initialized by initializing the data members within a constructor.
To deal with this problem, let’s take a look at another cool and enhanced technique i.e Constructor Member Initializer List in C++.
If using enumerate can make your Python code more efficient, why do so many developers overlook it? Are you one of them? Python Enumerate
Constructor Member Initializer List in C++
Constructor member initializer list is used in initializing the data members of a class in C++. The list of members to be initialized is indicated with the constructor as a comma-separated list followed by a colon.
Syntax:
Constructor_name(datatype value1, datatype value2) : data_member(value1), data_member(value2)
{
// Constructor Body
}
Example:
Example() : x(0), y(0) //Initializer list
{
std::cout << "Example Constructor Initialized" << std::endl;
}
// Parameterized Constructor
Example(int x1,int y1)
: x(x1), y(y1)
{
std::cout << "Example Parameterized Constructor Initialized" << std::endl;
}
Output:
Example Constructor Initialized
X: 0
Y: 0
Example Destructor Initialized
The Constructor Member Initializer list behaves same as default or parameterized constructor.
Note:
- We no longer need to do the assignments in the body of the constructor, as that element is replaced by the member initializer list.
- You may also remember that the member initializer list does not end in a semicolon.
- The Initializer list should be specified in the order set out in the class (If you don’t follow the order, some compilers might throw an error, otherwise they’ll correct it for you.).
Advantages of Constructor Member Initializer List
1. Elegant Constructor
When using the default or parametrized constructor, the constructor definition used to be loaded with all kinds of initialization, and the actual implementation of the constructor was written after the initialization of the data class members.
The constructor member initializer lists provide us with a simple way to initialise the class data members and the function definition is left empty to implement the constructor’s key logic.
2. Improves Performance
The Construct member initializer lists improves performance. Let’s see an example:
#include <iostream>
class Example2
{
private:
int x;
public:
Example2()
{
std::cout << "Example2 Default Constructor" << std::endl;
}
Example2(int x)
{
std::cout << "Example2 Parameterized Constructor with " << x << std::endl;
}
~Example2() {}
};
class Example1
{
private:
int x, y;
Example2 e2;
public:
Example1()
{
e2 = Example2(2);
}
Example1(int x1, int y1)
{
}
~Example1()
{
}
};
int main()
{
Example1 e;
}
Code Explaination:
In the above code, we have two classes Example1 and Example2. The Example1 class has a data member of type Example2 and the default constructor of Example1 is used to initialize the data member of Example2 type.
In the main function, an object of Example1 is created.
Output:
Example2 Default Constructor
Example2 Parameterized Constructor with 2
Let’s analyze the output:
In the output segment above, we can see that both the default and the parametrized constructors are called for the Example2 class. But why this happens when we just want the parameterized constructor to run.
This happens because Example2‘s default constructor gets called when we define the Example2 e2;
data member in the Example1 class and the parameterized constructor is called by Example1‘s default constructor.
This way two objects of Example2 class are created, while we need only one. This problem can be solved with the aid of a constructor member initializer list.
Solution
#include <iostream>
class Example2
{
private:
int x;
public:
Example2()
{
std::cout << "Example2 Default Constructor" << std::endl;
}
Example2(int x)
{
std::cout << "Example2 Parameterized Constructor with " << x << std::endl;
}
~Example2() {}
};
class Example1
{
private:
int x, y;
Example2 e2;
public:
Example1()
: e2(Example2(2))
{
}
Example1(int x1, int y1)
{
}
~Example1()
{
}
};
int main()
{
Example1 e;
}
Output:
Example2 Parameterized Constructor with 2
When using member initializer list, the instance of Example2 class is only created once and that too using the parameterized constructor.
When to use the member initializer list?
The Constructor member initializer list should be used when:
- Initializing non-static const data members
- Initializing reference members
- Initializing class-based data members (above example)
- Performance reasons
Further Reference:
- https://www.geeksforgeeks.org/when-do-we-use-initializer-list-in-c/
- https://en.cppreference.com/w/cpp/language/constructor