Object Oriented Programming in C++Unit 38 min read
Constructors & Destructors: Types, Initialization & Cleanup
Unit 3 of Object Oriented Programming in C++ covers constructors (default, parameterized, copy), destructors, initialization lists, and their roles in object lifecycle management, with real-world examples from banking, e-commerce, and system design.
TAKEAWAYS:
- Constructors initialize objects automatically when created, while destructors clean up resources automatically when objects are destroyed.
- Default constructors have no parameters, parameterized constructors customize object states, and copy constructors duplicate objects.
- Destructors release dynamically allocated memory and close files/resources to prevent leaks.
- Initialization lists (
: member(var)) are faster than assignment in constructors. - Constructors cannot return values or be inherited, but destructors must be virtual in polymorphic hierarchies.
Core Concepts: Constructors and Destructors
1. What is a Constructor?
A constructor is a special member function of a class that:
- Has the same name as the class.
- No return type (not even
void). - Called automatically when an object is created.
- Used to initialize object attributes.
Types of Constructors
classDiagram
class Constructor {
+ Default Constructor
+ Parameterized Constructor
+ Copy Constructor
}
class DefaultConstructor {
+ No parameters
+ Initializes with default values
}
class ParameterizedConstructor {
+ Takes arguments
+ Customizes object state
}
class CopyConstructor {
+ Takes an object of same class
+ Creates a copy
}
Constructor --> DefaultConstructor
Constructor --> ParameterizedConstructor
Constructor --> CopyConstructorExample: Bank Account Initialization
#include <iostream>
using namespace std;
class BankAccount {
private:
string accountHolder;
double balance;
public:
// Default Constructor
BankAccount() {
accountHolder = "Unnamed";
balance = 0.0;
}
// Parameterized Constructor
BankAccount(string name, double initialBalance) {
accountHolder = name;
balance = initialBalance;
}
// Copy Constructor
BankAccount(const BankAccount &other) {
accountHolder = other.accountHolder;
balance = other.balance;
}
void display() {
cout << "Holder: " << accountHolder << ", Balance: $" << balance << endl;
}
};
Trace: Object Creation
| Step | Code Execution | State After Execution |
|---|---|---|
| 1 | BankAccount acc1; |
acc1.accountHolder = "Unnamed", balance = 0 |
| 2 | BankAccount acc2("Ramesh", 5000); |
acc2.accountHolder = "Ramesh", balance = 5000 |
| 3 | BankAccount acc3 = acc2; |
acc3.accountHolder = "Ramesh", balance = 5000 (copy) |
In the Real World
eSewa (Nepal’s Digital Payment System)
- Uses constructors to initialize user accounts with default settings (e.g., zero balance, inactive status).
- Copy constructors help duplicate transaction records for auditing.
Khalti (Mobile Wallet)
- Parameterized constructors set up merchant accounts with predefined commission rates and currency types.
- Destructors ensure temporary session tokens are invalidated after use.
NTC (Nepal Telecom) Billing System
- Initialization lists efficiently set up customer records with prepaid/postpaid plans, avoiding slow assignments.
- Destructors release network resources when a call session ends.
2. Constructor Initialization Lists
- Faster than assignments inside the constructor body.
- Syntax:
: member(var)after the constructor declaration. - Mandatory for
constand reference members.
Example: Efficient Initialization
class Student {
private:
const int id;
int &marks; // Reference member
public:
Student(int i, int &m) : id(i), marks(m) {} // Initialization list
};
Trace: Initialization vs. Assignment
| Method | Code Example | Performance | Use Case |
|---|---|---|---|
| Initialization | Student s(101, marksRef) : id(101), marks(marksRef) |
Faster | const, references, objects |
| Assignment | Student s(101, marksRef); s.id = 101; |
Slower | Non-const members |
3. Destructors: Cleaning Up Resources
- Called automatically when an object goes out of scope or is deleted.
- No parameters, no return type.
- Used to free memory, close files, or release locks.
- Virtual in base classes for polymorphic destruction.
Example: Dynamic Memory Release
class DynamicArray {
private:
int *arr;
int size;
public:
DynamicArray(int s) { arr = new int[s]; size = s; }
~DynamicArray() { delete[] arr; } // Frees memory
};
Trace: Destructor Execution
sequenceDiagram
participant Main
participant obj
Main->>obj: DynamicArray arr(100);
Main->>obj: arr goes out of scope
obj->>obj: ~DynamicArray() called
obj->>System: delete[] arr4. Copy Constructor: Deep vs. Shallow Copy
| Feature | Shallow Copy | Deep Copy |
|---|---|---|
| Definition | Copies pointer addresses | Copies actual data pointed to |
| Risk | Dangling pointers if original is destroyed | Safe |
| Syntax | Default copy constructor | Manual implementation with new |
| Example | Student s2 = s1; (default) |
Custom copy constructor with new |
Example: Deep Copy in Linked List
class Node {
public:
int data;
Node *next;
Node(int val) : data(val), next(nullptr) {}
Node(const Node &other) { // Deep Copy Constructor
data = other.data;
next = new Node(*other.next); // Recursive deep copy
}
~Node() { delete next; }
};
Trace: Shallow vs. Deep Copy
Original List: A -> B -> C
Shallow Copy: A' -> B' -> C' (points to same memory as original!)
After delete original: A' -> B' -> C' (now dangling!)
Deep Copy: A'' -> B'' -> C'' (independent memory)
5. Constructor Overloading and Default Arguments
- Multiple constructors with different parameters.
- Default arguments allow flexible calls.
Example: Rectangle Area Calculator
class Rectangle {
private:
double length, width;
public:
Rectangle() : length(1.0), width(1.0) {} // Default
Rectangle(double l) : length(l), width(l) {} // Square
Rectangle(double l, double w) : length(l), width(w) {} // Rectangle
double area() { return length * width; }
};
Trace: Constructor Calls
| Call | Behavior |
|---|---|
Rectangle r1; |
length=1.0, width=1.0 |
Rectangle r2(5.0); |
Square: length=5.0, width=5.0 |
Rectangle r3(4, 6); |
Rectangle: length=4, width=6 |
6. Constructor and Destructor in Inheritance
- Derived class constructors call base class constructors (implicitly or explicitly).
- Destructors execute in reverse order (derived → base).
Example: Vehicle Hierarchy
class Vehicle {
public:
Vehicle() { cout << "Vehicle Constructor" << endl; }
~Vehicle() { cout << "Vehicle Destructor" << endl; }
};
class Car : public Vehicle {
public:
Car() { cout << "Car Constructor" << endl; }
~Car() { cout << "Car Destructor" << endl; }
};
Trace: Execution Order
Car obj;
Output:
Vehicle Constructor
Car Constructor
When obj is destroyed:
Car Destructor
Vehicle Destructor
Exam Tip
- Always explain the purpose of constructors/destructors (initialization vs. cleanup).
- Draw state diagrams for object creation/destruction (show memory allocation).
- Compare shallow vs. deep copy in exams—always prefer deep copy for dynamic memory.
- Mention initialization lists for
const/referencemembers (high-weight point). - For inheritance questions, state the order of constructor/destructor calls.
- Code traces are worth marks—show step-by-step variable changes.
Practice Question:
Write a program for a BankAccount class with:
- A parameterized constructor to set account number and balance.
- A copy constructor that performs a deep copy of transaction history (use
vector<string>). - A destructor to print "Account closed: [account number]". Trace the execution when:
- An object is created.
- A copy is made.
- The original is destroyed.
Based on the PU BE Computer (PU) syllabus for Object Oriented Programming in C++, unit 3.
Discussion
Loading…