What Is a Constructor in C++?
A constructor is a special member function of a class that is automatically called when an object is created.
The main purpose of a constructor is to initialize the data members of an object.
For example, imagine an embedded system containing a temperature sensor object. Before reading temperature values, the program may need to initialize variables, communication settings, or hardware-related parameters.
A constructor provides a structured way to perform such initialization when the object is created.
Important Characteristics of a Constructor
A constructor:
- Has the same name as the class.
- Does not have a return type.
- Is automatically called when an object is created.
- Can initialize class data members.
- Can be overloaded.
- Can be defined inside or outside the class.
The basic concept is simple: when an object is created, the constructor runs automatically.
Basic Constructor Syntax in C++
cpp
class Device
{
public:
Device()
{
// Initialization code
}
};
Now, when an object is created:
The constructor Device() is automatically called.
Unlike a normal member function, you do not need to call the constructor separately after creating the object.
Constructor Example in C++
Let us understand this with a simple example.
cpp
#include
using namespace std;
class Book
{
private:
int pages;
public:
Book()
{
pages = 250;
cout << "Book object created" << endl;
cout << "Number of pages: " << pages << endl;
}
};
int main()
{
Book b;
return 0;
}
How Does This Program Work?
When the statement below is executed:
the object b is created.
Immediately, the constructor Book() is called automatically.
Inside the constructor:
the member variable is initialized.
This is an example of a default constructor because no arguments are passed to the constructor.
Constructor vs Normal Function in C++
Students often ask an important question:
If a constructor contains code just like a function, how is it different from a normal function?
The answer is that constructors have special rules and are automatically connected to the lifecycle of an object.
| Constructor | Normal Function |
|---|
| Has the same name as the class | Can have a different name |
| Does not have a return type | Usually has a return type or void |
| Called automatically when an object is created | Usually called explicitly |
| Used mainly for object initialization | Used to perform specific operations |
| Cannot be virtual | A member function can be virtual |
The most important difference is automatic execution.
A normal function is generally called by the programmer. A constructor is automatically called when the corresponding object is created.
Types of Constructors in C++
The commonly discussed types of constructors are:
- Default Constructor
- Parameterized Constructor
- Copy Constructor
Each type is useful in different programming situations.
1. Default Constructor
A default constructor is a constructor that does not take arguments. It can initialize an object with predefined or default values.
Example
cpp
#include
using namespace std;
class Sensor
{
private:
int sensorID;
public:
Sensor()
{
sensorID = 101;
cout << "Sensor ID: " << sensorID << endl;
}
};
int main()
{
Sensor s1;
return 0;
}
When s1 is created, the constructor automatically initializes sensorID.
Suppose you create an object representing a device. You may want every new object to begin with safe default values.
For example:
cpp
Device()
{
status = 0;
errorCode = 0;
}
This helps ensure that the object begins in a predictable state.
In embedded programming, predictable initialization is important because uninitialized values can cause unexpected system behaviour.
2. Parameterized Constructor
A parameterized constructor accepts arguments when an object is created. This allows different objects to be initialized with different values.
Example
cpp
#include
using namespace std;
class Motor
{
private:
int speed;
public:
Motor(int s)
{
speed = s;
}
void display()
{
cout << "Motor Speed: " << speed << endl;
}
};
int main()
{
Motor m1(1000);
m1.display();
return 0;
}
Here:
creates the object and passes 1000 to the constructor. The constructor then initializes the speed variable.
Example: Calculating Values Using a Parameterized Constructor
cpp
#include
using namespace std;
class Bar
{
private:
int drink;
int people;
public:
Bar(int d, int p)
{
drink = d;
people = p;
}
int totalCash()
{
return drink * people;
}
};
int main()
{
Bar b(40, 35);
cout << "Total Cash Collected: "
<< b.totalCash();
return 0;
}
The constructor receives:
- 40 for
drink - 35 for
people
These values are stored in the object and later used by the totalCash() function.
Parameterized constructors are useful whenever objects require different initial values.
3. Copy Constructor in C++
A copy constructor creates a new object by initializing it from another object of the same class.
In simple terms: one object is used as the source for creating another object.
The general syntax is:
cpp
ClassName(const ClassName &object)
{
// Copy data
}
Example
cpp
#include
using namespace std;
class Sensor
{
private:
int value;
public:
Sensor(int v)
{
value = v;
}
Sensor(const Sensor &obj)
{
value = obj.value;
}
void display()
{
cout << "Sensor Value: "
<< value << endl;
}
};
int main()
{
Sensor s1(25);
Sensor s2 = s1;
s2.display();
return 0;
}
In this example:
uses s1 to initialize s2. The copy constructor copies the value from one object to another.
Copy constructors become particularly important when classes manage resources such as dynamically allocated memory or other resources that require careful copying.
What Is Constructor Overloading?
Just like normal functions, constructors can also be overloaded.
Constructor overloading means creating multiple constructors with the same name but different parameters. The compiler determines which constructor should be called based on the number or types of arguments provided.
Example
cpp
#include
using namespace std;
class Overload
{
private:
int result;
public:
Overload(int x, int y)
{
result = x * y;
}
Overload(int x, int y, int z)
{
result = x + y + z;
}
int getResult()
{
return result;
}
};
int main()
{
Overload o1(20, 4);
Overload o2(50, 65, 30);
cout << "Result 1: "
<< o1.getResult() << endl;
cout << "Result 2: "
<< o2.getResult() << endl;
return 0;
}
The first object:
calls the constructor with two parameters.
The second object:
calls the constructor with three parameters.
This flexibility is useful when an object can be initialized in different ways.
What Is a Destructor in C++?
A destructor is another special member function of a class.
While a constructor is called when an object is created, a destructor is automatically called when an object is destroyed or goes out of scope.
The destructor is commonly used to perform cleanup operations.
Destructor Characteristics
A destructor:
- Has the same name as the class.
- Uses a tilde (~) before the class name.
- Does not have a return type.
- Does not accept arguments.
- Is automatically called when an object’s lifetime ends.
The syntax is:
cpp
~ClassName()
{
// Cleanup code
}
Destructor Example in C++
cpp
#include
using namespace std;
class FormulaOne
{
private:
int speed;
int pickup;
public:
FormulaOne(int s, int p)
{
cout << "Constructor called" << endl;
speed = s;
pickup = p;
}
void display()
{
cout << "Speed: " << speed << endl;
cout << "Pickup: " << pickup << endl;
}
~FormulaOne()
{
cout << "Destructor called" << endl;
}
};
int main()
{
FormulaOne f(370, 4);
f.display();
return 0;
}
Expected Execution Flow
When the program creates:
the constructor runs first. The object is initialized with:
The display() function then prints the values.
When the object goes out of scope at the end of main(), the destructor is automatically called.
The execution sequence is therefore:
- Object is created.
- Constructor is called.
- Object performs its required operations.
- Object reaches the end of its lifetime.
- Destructor is called.
Difference Between Constructor and Destructor in C++
Constructors and destructors are special member functions that manage the lifecycle of an object, but they perform opposite roles.
| Constructor | Destructor |
|---|
| Initializes an object when it is created. | Performs cleanup when an object is destroyed. |
| Has the same name as the class. | Has the class name preceded by ~. |
| Can have parameters. | Cannot have parameters. |
| Can be overloaded. | Cannot be overloaded. |
| Called automatically when an object is created. | Called automatically when an object goes out of scope or is deleted. |
| Used to initialize data members and acquire resources. | Used to release resources and perform cleanup. |
| A class can have multiple constructors. | A class can have only one destructor. |
Example
cpp
class Student {
public:
Student() {
cout << "Constructor called";
}
~Student() {
cout << "Destructor called";
}
};
Here, the constructor runs when the Student object is created, while the destructor runs when the object is destroyed.
Constructors and Destructors in Embedded Systems
Now let us connect this concept with embedded systems programming.
In embedded C++ applications, classes may represent:
- Sensors
- Motors
- Communication interfaces
- UART modules
- SPI devices
- I2C peripherals
- GPIO controllers
- Timers
- Display modules
A constructor can be used to initialize the software state of these objects. For example:
cpp
class Motor
{
public:
Motor()
{
// Initialize default state
}
};
Similarly, a destructor can be used for cleanup associated with the object’s lifetime.
However, embedded developers must carefully understand resource usage. Embedded systems often have limited memory and strict timing requirements, so object creation, dynamic memory allocation, copying, and cleanup should be designed carefully according to the system requirements.
A Simple Embedded System Example
Consider a simplified sensor class.
cpp
#include
using namespace std;
class TemperatureSensor
{
private:
int sensorID;
public:
TemperatureSensor(int id)
{
sensorID = id;
cout << "Sensor initialized: "
<< sensorID << endl;
}
void readSensor()
{
cout << "Reading sensor: "
<< sensorID << endl;
}
~TemperatureSensor()
{
cout << "Sensor object cleanup completed"
<< endl;
}
};
int main()
{
TemperatureSensor sensor1(101);
sensor1.readSensor();
return 0;
}
This example demonstrates the complete object lifecycle.
When sensor1 is created:
cpp
TemperatureSensor sensor1(101);
the constructor initializes the object. The program then uses:
Finally, when the object goes out of scope, the destructor is called automatically.
Constructor and Destructor Execution Order
Understanding execution order is important.
For a simple object:
the constructor executes when the object is created. When the object leaves its scope, the destructor executes.
Object Created
↓
Constructor Called
↓
Object Used
↓
Object Lifetime Ends
↓
Destructor Called
This lifecycle management is one of the fundamental ideas behind Object-Oriented Programming in C++.
Important Points to Remember
When working with constructors and destructors in C++, remember these points:
Constructor
- Same name as the class.
- No return type.
- Called automatically when an object is created.
- Used to initialize objects.
- Can accept parameters.
- Can be overloaded.
Destructor
- Same name as the class with ~.
- No return type.
- Does not accept arguments.
- Called automatically when an object is destroyed or goes out of scope.
- Used for cleanup operations.
Final Thoughts
Understanding constructors and destructors in C++ is essential for every student learning Object-Oriented Programming and embedded C++ development.
A constructor helps ensure that an object starts with the required initial state. A destructor helps manage cleanup when that object’s lifetime ends.
As you move deeper into embedded systems, these concepts become part of larger topics such as object lifetime, memory management, hardware abstraction, resource management, and C++ application design.
The best way to master constructors and destructors is not just to memorize their definitions. Create small classes, initialize objects in different ways, experiment with parameterized and copy constructors, overload constructors, and observe exactly when destructors are called.
Once you understand the lifecycle of an object, many advanced C++ and embedded systems concepts become easier to understand.