ArtsAutosBooksBusinessEducationEntertainmentFamilyFashionFoodGamesGenderHealthHolidaysHomeHubPagesPersonal FinancePetsPoliticsReligionSportsTechnologyTravel
  • »
  • Technology»
  • Computers & Software»
  • Computer Science & Programming»
  • Programming Languages

C++ Constructor Initializer List - Explained with Example

Updated on January 9, 2017

1. Introduction

In this hub, I will explain what is "Constructor Initializer List" ? The initializer lists are useful to initialize the data member of a class. Actually, the constructor does this initialization stuff inside the body right?

2. A Class with a const data member

Let us say a class is having a const data member in it. Where should we initialize it? Well. Let us explore this with an example.

The class is written to calculate the area of the Circle for a given radius. It has a const data member, which holds the value for the Pi. The constructor of the class initializes data members radius, the const pi and calculates the area and stores it. The constructor is shown below:

	//Sample 03: This throws Error
	CCircle(float rad)
	{
		pi = 3.14159;
		m_radius = rad;
		m_Area = pi * m_radius * m_radius; 
 }

When we compile the code, we get the "Error C2758". Because the member "pi" is declared as const float pi;

Source
Source

3. Error C2758 and Constructor Initializer List

The error clearly indicated that the const members should be initialized with the constructor initializer list. The picture on the side shows the creating the initializer list:

As you see the initializer list is executed first before executing the very first statement that occurs in the body of the constructor. OK, going back to our example, we should modify our constructor so that it initializes the const pi in the initializer list. The modified constructor is shown below:

//Sample 04: Constructor with Initializer
CCircle(float rad) : pi(3.14159), 
	m_Area(pi * m_radius * m_radius),
	m_radius(rad) {}

Note that the list is having three initialization separated by a comma. Through the "Initializer List," we initialized pi, m_radius and also calculated m_area as well. But, some people prefer calculated values go inside the body of the constructor as it is going to use the already initialized member. The entire example is shown below:

//Example 01
#include "stdafx.h"
#include <iostream>
using namespace std;

class CCircle
{
// Sample 01: Members of Triangle class
private:
	const float pi;
	float m_radius;
	float m_Area;

public:
	//Sample 02: Method retruning a Calculated Area
	float GetArea()
	{
		return m_Area;
	}

	////Sample 03: This throws Error
	//CCircle(float rad)
	//{
	//	pi = 3.14159;
	//	m_radius = rad;
	//	m_Area = pi * m_radius * m_radius; 
	//	
	//}

	//Sample 04: Constructor with Initializer
	CCircle(float rad) : pi(3.14159), 
		m_Area(pi * m_radius * m_radius),
		m_radius(rad) {}
};

int main()
{
	//Sample 05: Creating the Circle object
	//			 with const member with it.
	CCircle objCircle(3);
	cout << endl;
	cout << "Area of Circle: " << objCircle.GetArea();
}

The result of executing the Program is shown below:

Source

4. Different Const data per Object

In the previous example, we bind the const value 3.14159 to the const data member pi. In some cases, each object needs its own const value. Say, for example, you are developing a Payroll processing application, which uses a class that represents a group of employees in the form of a department. Lets us say bonus for each department varies, but the same bonus is applied to all the employees within a department. In this case, the bonus is constant and const is bound to a value when the object is created. Look at the example given below:

//Example 02
#include "stdafx.h"
#include <iostream>
using namespace std;
class CEmployees
{
//Sample 01: Private members. 
private:
	float m_Emp1Salary;
	float m_Emp2Salary;
	float m_Emp3Salary;
	const float m_bunus_percent;

public:
	//Sample 02: Constrctor Initializer List
	CEmployees(float e1_sal, float e2_sal, float e3_sal,
		float PercentBonus): m_Emp1Salary(e1_sal),
		m_Emp2Salary(e2_sal),m_Emp3Salary(e3_sal),
		m_bunus_percent(PercentBonus)
	{}

	//Sample 02: Change Employee Salary
	void Change_Salary(int emp_no, float New_Salary)
	{
		if (emp_no == 1)
			m_Emp1Salary = New_Salary;
		if (emp_no == 2)
			m_Emp2Salary = New_Salary;
		if (emp_no == 3)
			m_Emp3Salary = New_Salary;
	}

	//Sample 03: Compute Bonus and Print
	void Print_SalaryandBonus()
	{
		cout << endl;
		cout << "Employee 1:" << endl;
		cout << "Salary = " << m_Emp1Salary << ", Bonus = " 
			<< m_Emp1Salary * m_bunus_percent / 100 << endl;

		cout << "Employee 2:" << endl;
		cout << "Salary = " << m_Emp2Salary << ", Bonus = " 
			<< m_Emp2Salary * m_bunus_percent / 100 << endl;

		cout << "Employee 3:" << endl;
		cout << "Salary = " << m_Emp3Salary << ", Bonus = " 
			<< m_Emp3Salary * m_bunus_percent / 100 << endl;
		cout << "==========================" << endl;
		cout << endl;
	}

};

int main()
{
	//Sample 04: Welding Deportment Employees
	CEmployees Welding_Emps(2000, 3000, 2500, 10);
	Welding_Emps.Print_SalaryandBonus();

	//Sample 05: Lathe Dept Employees
	CEmployees Lathe_Emps(1000,3700, 2000, 5);
	Lathe_Emps.Change_Salary(1, 6000);
	Lathe_Emps.Print_SalaryandBonus();
}

In the example, you can see that the bonus is declared as constant like const float m_bunus_percent;. But, the const is bind to a user-supplied value in the PercentBonus. The constructor initializer list is shown below:

//Sample 02: Constrctor Initializer List
CEmployees(float e1_sal, float e2_sal, float e3_sal,
	float PercentBonus): m_Emp1Salary(e1_sal),
	m_Emp2Salary(e2_sal),m_Emp3Salary(e3_sal),
	m_bunus_percent(PercentBonus)
{}

Look at the below two statement. We have two CEmployees objects Welding_Emps and Lathe_Emps. But, these objects while creating binds to different bonus percentage 10 and 5 respectively. The important thing about this is that constant objects cannot be changed after the binding is done. In our case, Welding_Emps have bonus percentage of 10 and Lathe Workers have the bonus percentage of 5. This example also uses the constructor initializer list and it is required as we have a constant member to hold the bonus percentage.

CEmployees Welding_Emps(2000, 3000, 2500, 10);
CEmployees Lathe_Emps(1000,3700, 2000, 5);


Output of the Example:




Source

In the output, you can see that the salary for the employee one is changed. But bonus percent cannot be changed from 5 percent for Lathe_Emps and 10 for Welding_Emps.

5. Initializer List Order

The order of the constructor initializer list is not important as initialization respects the order in which the object is laid out in the class template. But, it is a best practice to maintain the initializer list to match with the data member layout of the class. In the below example I have not maintained any order in the constructor initializer list that match with the member variable layout of the class template CGameCar. The constructor initializer list is shown below:

//Sample 04: GameCar Class
class CGameCar
{
private:
	CEngine m_engine;
	CTyres m_tyres;
	CGlass m_glass;
public:
	CGameCar():m_glass(3),m_tyres(2), m_engine(3){}
};

By looking at the above example you may think that the initialization order is m_glass, m_tyres and finally m_engine. But the initialization order is Engine, Tyres, and Glass. This is because the Objects lied out in the class template like that. This is shown below:

private:
	CEngine m_engine;
	CTyres m_tyres;
	CGlass m_glass;

The complete example and the output is shown below:

//Example 03
#include "stdafx.h"
#include <iostream>
using namespace std;

//Sample 01: The Engine Class
class CEngine
{
private:
	int m_x;
public:
	CEngine(int x) 
	{
		m_x = x;
		cout << "Engine Created" << endl;
	}
};

//Sample 02: Tyres Class
class CTyres
{
private:
	int m_x;
public:
	CTyres(int x) 
	{ 
		m_x = x;
		cout << "Tyres Created" << endl;
	}
};

//Sample 03: Glass Class
class CGlass
{
private:
	int m_x;
public:
	CGlass(int x) 
	{ 
		m_x = x;
		cout << "Front and Rear Glasses Created" << endl;
	}
};

//Sample 04: GameCar Class
class CGameCar
{
private:
	CEngine m_engine;
	CTyres m_tyres;
	CGlass m_glass;
public:
	CGameCar():m_glass(3),m_tyres(2), m_engine(3){}
};

//Sample 05: The Main method trying to create the GameCar class
int main()
{
	cout << endl;
	CGameCar car1;
	return 0;
}

Output:

Source

So, again, the order is based on the Layout of the class template and the order in which the initializer list is formed. It will be best practice to maintain the same order in the class layout as well as initializer list as well. This will help a user to know about the initialization order without looking the class layout.

Summary

You saw that a constructor initializer list is useful to assign a value to the const data member. Then with an example, we saw how do we have different objects of the same class type having a different constant value. Finally, this hub showed you the order of initializer list does nothing but the layout of the class will.

You should note that the Constructor initializer list is useful to bind the reference data member as well.

Vote it:

Did you ever confused with the Initializer List order (when the order is different from the class Layout)?

See results

Comments

    0 of 8192 characters used
    Post Comment

    • sirama profile image
      Author

      sirama 4 years ago

      Thank you jabelufiroz

    • jabelufiroz profile image

      Firoz 4 years ago from India

      C++ legend. Voted up.