Skip to main content

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.

L1

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).
TraitMeaning
NameSame as the class name
Return typeNone
When calledAutomatically at object creation
PurposeInitialize data members / acquire resources
OverloadingYes — 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).
TypeSignature ideaWhen it runsReal-life
DefaultClassName()Object with no args: T t;Empty cart ready to use
ParameterizedClassName(args…)T t(10, "A");Account opened with initial deposit
CopyClassName(const ClassName&)T b = a; / T b(a);Photocopy of a filled form
Move (overview)ClassName(ClassName&&)Steal from temporaryTransfer 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 const members 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 delete a heap object.
  • Use to release resources: delete memory, 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.
PointConstructorDestructor
PurposeInitialize objectClean up object
NameSame as class~ + class name
ParametersCan take (overloads)None
OverloadingYesNo
When calledObject creationObject destruction
Return typeNoneNone
Typical workSet members / newdelete / close resources
Real-lifeOpen account / start sessionClose account session / checkout

When are they called? (order)

  • For a local object: constructor at definition, destructor at end of block.
  • For new objects: constructor at new, destructor at delete (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
*/
L2

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 explicit to 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.
  • Array wrapper: ctor allocates, copy ctor deep-copies, dtor frees.
  • Config object loaded from file in ctor; flushes/closes in dtor.
L3

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.

L4

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;
}
L5

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.
L6

Practice Programs List

  1. Write a class with default constructor that sets name to "Guest".
  2. Add a parameterized constructor to Student(roll, name) and display.
  3. Overload constructors for Time: (), (seconds), (min, sec).
  4. Demonstrate copy construction of a Point and print both objects.
  5. Show constructor/destructor messages for three local objects; note reverse dtors.
  6. Create a class with a const id initialized only via initializer list.
  7. Write a Buffer that new[]s in ctor and delete[]s in dtor.
  8. Intentionally shallow-copy a pointer-owning class (in a throwaway demo), then fix with deep copy.
  9. Delete the copy constructor of a class and observe the compile error on copy.
  10. Build BankAccount(balance) with deposit/withdraw; print on destroy remaining balance in dtor (demo).
  11. Compare initialization with : x(v) vs assigning x = v inside the body for a simple type.
  12. List four real-life objects and what their constructors/destructors would do.
  13. Explain Rule of Three in your own words with a pointer example.
  14. Write explicit Degree(int) and show why Degree d = 10; may be blocked.