Intermediate 12 min

Constructors

Master constructors to automatically initialize objects correctly and prevent bugs from uninitialized data

Learn how constructors automatically initialize objects and why they are essential for writing reliable C++ code.

A Simple Example

#include <iostream>
#include <string>

class Player {
public:
    std::string name;
    int health;
    int maxHealth;
    int level;

    // Default constructor (no parameters)
    Player() {
        name = "Unknown";
        health = 100;
        maxHealth = 100;
        level = 1;
        std::cout << "Default constructor called for " << name << "\n";
    }

    // Parameterized constructor
    Player(std::string playerName, int hp) {
        name = playerName;
        health = hp;
        maxHealth = hp;
        level = 1;
        std::cout << "Parameterized constructor called for " << name << "\n";
    }

    // Constructor with all parameters
    Player(std::string playerName, int hp, int lvl) {
        name = playerName;
        health = hp;
        maxHealth = hp;
        level = lvl;
        std::cout << "Full constructor called for " << name << "\n";
    }

    void display() {
        std::cout << name << " (Level " << level << ") - HP: " << health << "/" << maxHealth << "\n";
    }
};

int main() {
    Player player1;  // Uses default constructor
    player1.display();

    Player player2{"Aria", 150};  // Uses parameterized constructor
    player2.display();

    Player player3{"Zorn", 200, 10};  // Uses full constructor
    player3.display();

    return 0;
}

Breaking It Down

Default Constructor

  • What it does: Initializes objects when no arguments are provided
  • Syntax: ClassName() { /* initialization code */ }
  • Use for: Providing sensible default values (e.g., empty name, zero health)
  • Remember: If you define ANY constructor, the compiler stops generating the default one automatically

Parameterized Constructors

  • What it does: Allows custom initialization with specific values
  • Multiple versions: You can have several constructors with different parameters
  • Called overloading: Having multiple constructors with different parameter lists
  • Remember: The compiler chooses which constructor to call based on the arguments you provide

Constructor Execution

  • When called: Automatically executed when an object is created
  • Cannot be called directly: You cannot call obj.Constructor() like a normal method
  • Runs before use: Ensures all members are initialized before any other code uses the object
  • Remember: Every object creation triggers exactly one constructor

Initialization Lists (Advanced)

  • What it is: The : member{value} syntax after constructor parameters
  • Why use it: More efficient than assignment in the constructor body
  • Direct initialization: Members are constructed with correct values immediately
  • Remember: For complex types like std::string, this avoids creating then copying

Why This Matters

  • Uninitialized variables are dangerous - they contain random garbage values that cause unpredictable behavior.
  • Constructors guarantee that every object starts in a valid state.
  • This is not just convenient, it is essential for writing reliable software.
  • Professional C++ code always uses constructors to ensure objects are ready to use the moment they are created.

Critical Insight

Use initialization lists (the : syntax) instead of assignment in the constructor body. It is more efficient because members are initialized directly rather than default-constructed then assigned. For complex objects, this can make a significant performance difference:

// Less efficient (default constructs then assigns)
MyClass(std::string n) {
    name = n;  // Creates default string, then copies n into it
}

// More efficient (direct initialization)
MyClass(std::string n) : name{n} {  // Directly constructs name with n
}

Best Practices

Use initialization lists: Prefer MyClass(int x) : member{x} {} over assignment in the constructor body for better performance.

Initialize all members: Every member variable should be initialized in every constructor to prevent garbage values.

Provide a default constructor: If users might create objects without parameters, provide a default constructor with sensible defaults.

Validate parameters: Check that constructor arguments are valid (e.g., positive dimensions, non-empty strings) before using them.

Common Mistakes

Forgetting to initialize all members: Leaving some member variables uninitialized defeats the purpose of constructors.

Assignment instead of initialization: Using assignment in the constructor body instead of initialization lists is less efficient.

Not validating parameters: Accepting invalid values (negative dimensions, empty strings) without checking.

Defining one constructor kills the default: If you define ANY constructor, the compiler will not auto-generate a default constructor.

Debug Challenge

This Rectangle constructor works but is inefficient. Click the highlighted line to improve it using modern C++ initialization:

1 #include <iostream>
2
3 class Rectangle {
4 public:
5 int width;
6 int height;
7
8 Rectangle(int w, int h) {
9 width = w;
10 height = h;
11 }
12 };

Quick Quiz

  1. What happens when you create an object without providing constructor arguments?
The default constructor is called
Compilation error
Members are left uninitialized
  1. Which is more efficient?
`MyClass(int x) : member{x} {}`
`MyClass(int x) { member = x; }`
They are exactly the same
  1. Can a class have multiple constructors?
Yes, through constructor overloading
No, only one constructor allowed
Yes, but only two maximum

Practice Playground

Time to try out what you just learned! Play with the example code below, experiment by making changes and running the code to deepen your understanding.

Lesson Progress

  • Fix This Code
  • Quick Quiz
  • Practice Playground - run once