C++ OOP
Constructors & Destructors
Complete lesson for Constructors & Destructors using LEARNCODEGURU’s 6-level learning model — from basics to advanced practice, with C++ OOP and STL where relevant.
Basics — Constructors & Destructors
Section: C++ OOP. C++ constructors and destructors — types, initializer lists, cleanup, and when each runs.
What is a constructor?
- A **constructor** is a special member function that **initializes** an object when it is created.
- Same name as the class; **no return type** (not even
void). - Called **automatically** when an object is created.
- Can be **overloaded** (default, parameterized, copy, …).
- **Real-life:** opening a new bank account — set account number and starting balance as soon as the account exists.
- **Real-life:** buying a phone — it comes powered on with factory settings (initialized state).
| Trait | Meaning |
|---|---|
| Name | Same as the class name |
| Return type | None |
| When called | Automatically at object creation |
| Purpose | Initialize data members / acquire resources |
| Overloading | Yes — multiple constructors allowed |
#include <iostream>
#include <string>
using namespace std;
class Student {
private:
int roll;
string name;
public:
Student() { // constructor
roll = 0;
name = "Unknown";
cout << "Student created\n";
}
void show() const {
cout << roll << " " << name << "\n";
}
};
int main() {
Student s; // constructor runs here
s.show();
return 0;
} Types of constructors
- Main kinds you will use early: **default**, **parameterized**, and **copy**.
- Later: **move** constructor (Advanced C++ / move semantics).
| Type | Signature idea | When it runs | Real-life |
|---|---|---|---|
| Default | ClassName() | Object with no args: T t; | Empty cart ready to use |
| Parameterized | ClassName(args…) | T t(10, "A"); | Account opened with initial deposit |
| Copy | ClassName(const ClassName&) | T b = a; / T b(a); | Photocopy of a filled form |
| Move (overview) | ClassName(ClassName&&) | Steal from temporary | Transfer ownership of a locker key |
Default constructor
- Takes **no parameters** (or all defaults).
- If you write **no** constructor, the compiler often provides a default one (until you add your own rules).
- If you declare any constructor, you may need to define/default the default ctor yourself:
Class() = default;.
class Counter {
private:
int n;
public:
Counter() { n = 0; } // default constructor
int get() const { return n; }
};
Counter c; // uses default constructor Parameterized constructor
- Takes arguments to set initial state.
- Allows creating objects with different starting values.
- **Real-life:**
Rectangle(10, 5)sets length and width at birth.
#include <iostream>
using namespace std;
class Rectangle {
private:
int length, width;
public:
Rectangle(int l, int w) {
length = l;
width = w;
}
int area() const { return length * width; }
};
int main() {
Rectangle r(10, 5);
cout << r.area() << "\n"; // 50
return 0;
} Constructor overloading
- Multiple constructors with different parameter lists — same idea as function overloading.
- Compiler picks the matching constructor from how you create the object.
#include <iostream>
#include <string>
using namespace std;
class Box {
private:
int side;
string label;
public:
Box() : side(1), label("small") {}
Box(int s) : side(s), label("custom") {}
Box(int s, string lab) : side(s), label(lab) {}
void show() const {
cout << label << " side=" << side << "\n";
}
};
int main() {
Box a;
Box b(5);
Box c(8, "gift");
a.show(); b.show(); c.show();
return 0;
} Copy constructor
- Creates a new object as a **copy** of an existing object.
- Typical signature:
ClassName(const ClassName& other); - Called for:
T b(a);,T b = a;(initialization), pass-by-value, return-by-value (often). - Default member-wise copy is fine for simple types; **dangerous** if the class owns raw pointers (shallow copy).
- **Real-life:** photocopy of a document — a second independent paper with the same text.
#include <iostream>
using namespace std;
class Point {
private:
int x, y;
public:
Point(int a, int b) : x(a), y(b) {}
Point(const Point& p) : x(p.x), y(p.y) {
cout << "Copy constructor\n";
}
void show() const { cout << "(" << x << "," << y << ")\n"; }
};
int main() {
Point a(2, 3);
Point b(a); // copy constructor
b.show();
return 0;
} Initializer list
- Syntax:
Constructor(...) : member1(val1), member2(val2) { }. - Preferred way to initialize members — especially
constmembers and references (must use initializer list). - Can be more efficient than assigning inside the body.
class Player {
private:
const int id;
string name;
public:
Player(int i, string n) : id(i), name(n) {
// id must be set in the initializer list
}
}; What is a destructor?
- A **destructor** cleans up when an object’s lifetime **ends**.
- Name:
~ClassName()— tilde + class name; no parameters, no return type, cannot be overloaded. - Called **automatically** when the object goes out of scope, or when you
deletea heap object. - Use to release resources:
deletememory, close files, unlock, etc. (RAII). - **Real-life:** checking out of a hotel — return the key and free the room when you leave.
#include <iostream>
using namespace std;
class Tracer {
public:
Tracer() { cout << "Constructed\n"; }
~Tracer() { cout << "Destroyed\n"; }
};
int main() {
Tracer t; // Constructed
cout << "Inside main\n";
return 0;
} // Destroyed here Differences between constructor and destructor
- Initialization vs cleanup — opposite ends of an object’s life.
| Point | Constructor | Destructor |
|---|---|---|
| Purpose | Initialize object | Clean up object |
| Name | Same as class | ~ + class name |
| Parameters | Can take (overloads) | None |
| Overloading | Yes | No |
| When called | Object creation | Object destruction |
| Return type | None | None |
| Typical work | Set members / new | delete / close resources |
| Real-life | Open account / start session | Close account session / checkout |
When are they called? (order)
- For a local object: constructor at definition, destructor at end of block.
- For
newobjects: constructor atnew, destructor atdelete(or smart pointer release). - Multiple objects: constructors in creation order; destructors in **reverse** order.
#include <iostream>
using namespace std;
class A {
int id;
public:
A(int i) : id(i) { cout << "Ctor " << id << "\n"; }
~A() { cout << "Dtor " << id << "\n"; }
};
int main() {
A a1(1);
A a2(2);
return 0;
}
/* Output order:
Ctor 1
Ctor 2
Dtor 2
Dtor 1
*/ Advanced — Constructors & Destructors
Deep copy vs shallow copy
- Default copy copies pointer addresses (**shallow**) — two objects may delete the same memory twice.
- If you own a resource (
new), write a **deep** copy constructor (and destructor, and assignment) — Rule of Three. - Prefer
unique_ptr/ containers so you often need no custom copy/destroy.
class Buffer {
int* data;
int n;
public:
Buffer(int size) : n(size), data(new int[size]{}) {}
Buffer(const Buffer& other) : n(other.n), data(new int[other.n]) {
for (int i = 0; i < n; i++) data[i] = other.data[i]; // deep copy
}
~Buffer() { delete[] data; }
}; Rule of Three / Five (overview)
- **Rule of Three:** if you need a custom destructor, copy constructor, or copy assignment — you usually need all three.
- **Rule of Five:** also consider move constructor and move assignment in modern C++.
- **Rule of Zero:** design types so default special members are enough (use RAII members).
=default and =delete
Class() = default;asks the compiler to generate the default constructor.Class(const Class&) = delete;forbids copying (useful for unique ownership).- Deleting copy is common for resource handles and
unique_ptr-like types.
class FileHandle {
public:
FileHandle() = default;
FileHandle(const FileHandle&) = delete;
FileHandle& operator=(const FileHandle&) = delete;
}; Delegating and converting constructors (overview)
- A constructor can call another constructor of the same class (delegating) in C++11.
- A single-argument constructor can act as a conversion — mark
explicitto block surprising implicit conversions.
class Degree {
int value;
public:
explicit Degree(int v) : value(v) {}
}; Real-life models
- Game
Player(name, health)parameterized ctor; destructor logs “player left”. - Database connection object: ctor connects, dtor disconnects.
Arraywrapper: ctor allocates, copy ctor deep-copies, dtor frees.- Config object loaded from file in ctor; flushes/closes in dtor.
Tricky Interview Points
Q1) What is a constructor?
Answer A special member function with the same name as the class, no return type, called automatically to initialize a new object.
Q2) What is a destructor?
Answer A special member function named ~ClassName that cleans up when an object is destroyed. It takes no parameters and cannot be overloaded.
Q3) Types of constructors?
Answer Default, parameterized, copy, and (in modern C++) move constructors. Constructors can be overloaded.
Q4) Difference between constructor and destructor?
Answer Constructor initializes at creation and can be overloaded with parameters. Destructor cleans up at destruction, has no parameters, and cannot be overloaded.
Q5) When is a copy constructor called?
Answer When an object is initialized from another object (T b(a); or T b = a;), and typically when passing/returning objects by value.
Q6) What is an initializer list?
Answer The : member(value), ... list before the constructor body used to initialize members. Required for const members and references.
Q7) Can a constructor be virtual?
Answer No. Destructors can be virtual (important for polymorphic base classes), but constructors cannot.
Q8) What is the Rule of Three?
Answer If a class needs a custom destructor, copy constructor, or copy assignment operator for resource management, it usually needs all three.
Q9) Why is shallow copy dangerous with raw pointers?
Answer Two objects share the same heap memory; when both destructors run, you get double-delete undefined behaviour.
Q10) Does C++ provide a default constructor automatically?
Answer Often yes if you declare no constructors. If you declare others, a default constructor may not exist unless you define or =default it.
Q11) Order of constructor/destructor calls for multiple locals?
Answer Constructors run in creation order; destructors run in reverse order at scope exit.
Q12) Why mark a single-argument constructor explicit?
Answer To prevent unintended implicit conversions from that argument type to the class type.
Simple Programs
Default constructor message
#include <iostream>
using namespace std;
class Hello {
public:
Hello() { cout << "Hello constructed\n"; }
~Hello() { cout << "Hello destroyed\n"; }
};
int main() {
Hello h;
return 0;
} Parameterized Rectangle
#include <iostream>
using namespace std;
class Rectangle {
int l, w;
public:
Rectangle(int a, int b) : l(a), w(b) {}
int area() const { return l * w; }
};
int main() {
Rectangle r(4, 6);
cout << r.area() << "\n";
return 0;
} Overloaded constructors
#include <iostream>
using namespace std;
class Timer {
int seconds;
public:
Timer() : seconds(0) {}
Timer(int s) : seconds(s) {}
Timer(int m, int s) : seconds(m * 60 + s) {}
int get() const { return seconds; }
};
int main() {
Timer a, b(10), c(1, 5);
cout << a.get() << " " << b.get() << " " << c.get() << "\n";
return 0;
} Copy constructor demo
#include <iostream>
using namespace std;
class Num {
int v;
public:
Num(int x) : v(x) {}
Num(const Num& n) : v(n.v) { cout << "copied\n"; }
int get() const { return v; }
};
int main() {
Num a(7);
Num b(a);
cout << b.get() << "\n";
return 0;
} Destructor reverse order
#include <iostream>
using namespace std;
class A {
char id;
public:
A(char c) : id(c) { cout << "Ctor " << id << "\n"; }
~A() { cout << "Dtor " << id << "\n"; }
};
int main() {
A x('X');
A y('Y');
return 0;
} Initializer list with const member
#include <iostream>
using namespace std;
class Badge {
const int id;
public:
Badge(int i) : id(i) {}
int getId() const { return id; }
};
int main() {
Badge b(42);
cout << b.getId() << "\n";
return 0;
} Simple RAII buffer
#include <iostream>
using namespace std;
class Buffer {
int* data;
public:
Buffer(int n) : data(new int[n]{}) {
cout << "allocated\n";
}
~Buffer() {
delete[] data;
cout << "freed\n";
}
};
int main() {
Buffer buf(10);
return 0;
} Problem Solving Tricks
- Constructor name = class name; destructor = ~ClassName.
- No return type on either.
- Prefer initializer lists over body assignment.
- const members and references must use initializer lists.
- Overload constructors for different creation styles.
- Destructors run automatically — use them for cleanup (RAII).
- Multiple locals: destroy in reverse order of construction.
- If you new in ctor, delete in dtor (or use smart pointers).
- Custom destructor + raw owning pointer ⇒ think Rule of Three.
- Use =delete to forbid copying when it does not make sense.
- Mark converting constructors explicit when implicit conversion is risky.
- Print ctor/dtor messages while learning call order.
Practice Programs List
- Write a class with default constructor that sets name to "Guest".
- Add a parameterized constructor to Student(roll, name) and display.
- Overload constructors for Time: (), (seconds), (min, sec).
- Demonstrate copy construction of a Point and print both objects.
- Show constructor/destructor messages for three local objects; note reverse dtors.
- Create a class with a const id initialized only via initializer list.
- Write a Buffer that new[]s in ctor and delete[]s in dtor.
- Intentionally shallow-copy a pointer-owning class (in a throwaway demo), then fix with deep copy.
- Delete the copy constructor of a class and observe the compile error on copy.
- Build BankAccount(balance) with deposit/withdraw; print on destroy remaining balance in dtor (demo).
- Compare initialization with : x(v) vs assigning x = v inside the body for a simple type.
- List four real-life objects and what their constructors/destructors would do.
- Explain Rule of Three in your own words with a pointer example.
- Write explicit Degree(int) and show why Degree d = 10; may be blocked.