Skip to content

Latest commit

 

History

History

README.md

Constructors and Destructors - Interview Preparation

🔗 Quick Links

�📚 Topics Covered

Part 1: Constructor Basics ✅

Part 2: Parameterized Constructors ✅

Part 3: Copy Constructor ✅

Part 4: Constructor Overloading ✅

Part 5: Constructor Initialization List ✅

  • Member initialization list syntax
  • Why use it? (Performance & Efficiency)
  • When is it mandatory? (const, reference, objects without default constructor)
  • Initialization vs Assignment
  • Initialization order (declaration order matters!)
  • File: 05_initialization_list.cpp

Deep Dive Explanation: See detailed explanation below

Part 6: Destructors ✅

Part 7: Constructor & Destructor Order ✅

Part 8: Special Cases ✅

  • Explicit keyword (prevent implicit conversions)
  • Private Constructors (Singleton, Factory patterns)
  • Delegating Constructors (C++11)
  • Delete/Default keywords (C++11)
  • File: 08_special_cases.cpp

Deep Dive Explanation: See explicit keyword explanation below

Part 9: Real-World Examples

Part 10: Interview Questions


🎯 Interview Key Points to Remember

Constructors:

  • Same name as class, no return type
  • Called automatically when object is created
  • Can be overloaded
  • Types: Default, Parameterized, Copy
  • Initialization list vs assignment in constructor body
  • Cannot be virtual

Destructors:

  • Name: ~ClassName()
  • No parameters, no return type
  • Only one destructor per class
  • Called when object goes out of scope
  • Should be virtual in base class if inheritance is used
  • Used for cleanup (deallocate memory, close files, etc.)

🚀 Progress Tracker

  • Part 1: Basic Constructor
  • Part 2: Parameterized Constructor
  • Part 3: Copy Constructor
  • Part 4: Constructor Overloading
  • Part 5: Initialization List
  • Part 6: Destructors
  • Part 7: Constructor/Destructor Order
  • Part 8: Special Cases ✅ COMPLETED!
  • Part 9: Real-World Examples (Optional)
  • Part 10: Interview Questions (Optional)

📖 Detailed Explanations

Initialization List: Why More Efficient?

Performance Comparison

Without Initialization List (Assignment in Body):

class Student {
    string name;
    int age;
public:
    Student(string n, int a) {
        name = n;  // Assignment
        age = a;
    }
};

What happens behind the scenes:

Step 1: Default constructor called AUTOMATICALLY
        name = string();     // Empty string created
        age = int();         // Default int

Step 2: Assignment in constructor body
        name = n;            // Destroy old, assign new
        age = a;

Step 3: Cleanup (for complex types)

Total operations for 'name': 3 steps
Time: ███

With Initialization List:

class Student {
    string name;
    int age;
public:
    Student(string n, int a) : name(n), age(a) {
        // Members ALREADY initialized!
    }
};

What happens behind the scenes:

Step 1: Direct construction with value
        name = string(n);    // Construct directly
        age = a;             // Direct initialization

Total operations for 'name': 1 step
Time: █

Efficiency Breakdown

Method Operations Time Complexity
Assignment Default construct → Assign → Cleanup O(3)
Initialization List Direct construction O(1)

Impact: For complex types (string, vector, objects), initialization list is significantly faster!


Object Creation Timeline

Understanding "When Do Variables Exist?"

Class = Blueprint (No memory allocated)

class Student {
    string name;  // Just a declaration, no memory yet!
    int age;      // Just a declaration, no memory yet!
};
// At this point: NO OBJECT EXISTS

Object Creation Process:

Step 1: Memory Allocation
┌─────────────────┐
│ Memory for obj  │  ← Space allocated
│   - name: ???   │
│   - age: ???    │
└─────────────────┘

Step 2: Initialization List Executes
┌─────────────────┐
│ Memory for obj  │
│   - name: value │  ← Initialized directly
│   - age: value  │  ← Initialized directly
└─────────────────┘

Step 3: Constructor Body Executes
   (Additional logic if any)

Step 4: Object Ready!
   Variables now exist and are usable

Analogy: Building a House

📋 Class Definition = Blueprint
   - Room 1: Living room
   - Room 2: Bedroom
   (No actual house exists yet!)

🏗️ Object Creation = Construction Process:
   Step 1: Allocate land (memory allocation)
   Step 2: Build rooms (initialization list)
   Step 3: Interior decoration (constructor body)
   
🏠 Object Complete
   - Rooms exist with furniture
   - House is ready to use

Timeline Example:

// Before: No object, no variables exist
Student s1("John", 20);  // Object creation starts!

// During creation:
// 1. Memory allocated for s1
// 2. Initialization list: name="John", age=20
// 3. Constructor body runs
// 4. Object ready

// After: s1 exists, name and age exist in memory

Key Interview Points

Q: Why is initialization list more efficient?

It directly constructs members with given values in one step, whereas assignment first default-constructs members, then assigns new values (two steps). This matters especially for complex types like strings, vectors, and objects.

Q: When do member variables come into existence?

Member variables come into existence when an object is created. Memory is allocated, then the initialization list runs to initialize members, then the constructor body executes. Before object creation, the class is just a blueprint.

Q: When MUST you use initialization list?

  • Const member variables (cannot be assigned after creation)
  • Reference member variables (must be initialized)
  • Member objects without default constructors
  • Calling base class constructors (inheritance)

Explicit Keyword: Preventing Implicit Conversions

The Problem: Implicit Type Conversion

Without explicit keyword:

class Distance {
    int meters;
public:
    Distance(int m) : meters(m) { }  // Single-parameter constructor
};

// This WORKS but might be unintended!
Distance d = 100;  // int implicitly converted to Distance

What C++ compiler does automatically:

Step 1: Sees you want Distance object
Step 2: Sees you provided int (100)
Step 3: Finds constructor Distance(int)
Step 4: Automatically calls Distance(100)
Step 5: Distance d = 100; becomes Distance d = Distance(100);

This is called IMPLICIT TYPE CONVERSION - compiler does it automatically without asking you!

Why This Can Be Dangerous

Real-world example:

class BankAccount {
    double balance;
public:
    BankAccount(double bal) : balance(bal) { }
};

void withdraw(BankAccount acc) {
    // Process withdrawal from account
}

// Later in code:
withdraw(5000);  // 🚨 DANGER! What does this mean?

The problem:

  • Did you mean account ID 5000?
  • Or create NEW account with balance ₹5000?
  • Code compiles but does WRONG thing!
  • C++ silently creates temporary BankAccount(5000) - BUG!

The Solution: explicit Keyword

class Distance {
    int meters;
public:
    explicit Distance(int m) : meters(m) { }
};

// Now:
Distance d = 100;              // ❌ ERROR! Implicit conversion blocked
Distance d(100);               // ✓ OK - Direct initialization
Distance d = Distance(100);    // ✓ OK - Explicit conversion

What explicit does:

  • Tells compiler: "Don't automatically convert for me!"
  • Forces programmer: "Be explicit about what you want!"
  • Prevents bugs: No accidental conversions

Visual Understanding

WITHOUT explicit:
==================
int (100) ──→ [Automatic Magic ✨] ──→ Distance object
             (Compiler does this silently!)


WITH explicit:
==================
int (100) ──X──→ Distance object  (BLOCKED!)
                  ↓
             Must explicitly say:
             Distance(100) ✓
             Distance d = Distance(100); ✓

When to Use explicit

Modern C++ Best Practice (Scott Meyers - Effective C++):

"Make constructors explicit by default. Only remove it if you have a good reason."

// ✅ DEFAULT: Always start with explicit
class MyClass {
public:
    explicit MyClass(int value) { }
};

// ❌ RARE: Only remove if you specifically want implicit conversion
class MyClass {
public:
    MyClass(int value) { }  // After careful consideration only!
};

Exceptions (Rare Cases)

Some standard library types intentionally allow implicit conversion:

// std::string allows implicit conversion - by design
std::string s = "hello";  // char* → string (convenient!)

// std::complex allows implicit conversion
std::complex<double> c = 3.14;  // double → complex (makes sense!)

But these are carefully designed! For your classes: use explicit by default.

Interview Answer

Q: What is the explicit keyword and when should you use it?

A: The explicit keyword prevents single-parameter constructors from being used for implicit type conversions.

  • Without explicit: Distance d = 100; works (compiler silently converts int → Distance)
  • With explicit: Distance d = 100; gives compile error, must use Distance d(100);

Why use it? Prevents accidental bugs from unintended type conversions. Makes code intentions clear and compiler catches mistakes at compile-time.

Best practice: Make ALL single-parameter constructors explicit unless you specifically want implicit conversion. It's the safe default in modern C++.

Think of explicit as a safety belt - always wear it! 🔒