Back to C++
2026-03-268 min read

constructor (C++)

Learn constructor (C++) step by step with clear examples and exercises.

Why This Matters

Welcome to this full guide on C++ class constructors and destructors! In this tutorial, we will delve deep into the essential concepts of these powerful tools that every C++ programmer should master. We'll cover practical examples, common mistakes, and interview-ready one-liners to help you excel in coding challenges and real-world projects.

Why This Matters

Constructors and destructors are crucial components of object-oriented programming in C++. They ensure proper initialization and cleanup of objects, which is vital for writing robust and efficient code. Understanding these concepts will help you avoid common bugs, handle memory management effectively, and write cleaner, more maintainable code.

Prerequisites

Before diving into the core concept, it's essential to have a good grasp of the following topics:

  • C++ basics: variables, data types, operators, loops, functions, and arrays
  • Object-oriented programming concepts: classes, objects, inheritance, and polymorphism

Core Concept

Constructors

A constructor is a special function that gets called automatically when an object of a class is created. Its primary purpose is to initialize the data members of the class with appropriate values. A class can have multiple constructors with different parameters, which allows for flexible object initialization.

Default Constructor

When no constructor is explicitly defined in a class, a default constructor with no arguments is automatically generated by the compiler. This default constructor initializes all data members to their default values (zero for numeric types and null pointers for pointer types).

class MyClass {
int num;
public:
MyClass() : num(0) {} // Default constructor body
};

Parameterized Constructor

To create a parameterized constructor, you define a constructor with one or more parameters. When creating an object of the class, you pass the required arguments to the constructor.

class MyClass {
int num;
public:
MyClass(int value) : num(value) {} // Parameterized constructor initializes data member 'num' with 'value'
};

// Creating an object and passing an argument to the constructor
MyClass obj(10);

Constructor Overloading

Constructor overloading allows you to define multiple constructors within a class that have different numbers or types of parameters. This enables flexible initialization of objects based on the user's needs.

class MyClass {
int num;
public:
MyClass() : num(0) {} // Default constructor
MyClass(int value) : num(value) {} // Parameterized constructor
MyClass(double value) : num(static_cast<int>(value)) {} // Constructor for double values
};

// Creating objects with different constructors
MyClass obj1; // Calls the default constructor (no arguments)
MyClass obj2(10); // Calls the parameterized constructor (with an integer argument)
MyClass obj3(10.5); // Calls the constructor for double values (converts the argument to an integer)

Initializer Lists

C++11 introduced initializer lists, which allow you to initialize data members using a list of comma-separated expressions within curly braces {}. This can be useful when dealing with complex initialization scenarios.

class MyClass {
public:
MyClass(int a, int b, int c) : num1(a), num2(b), num3(c) {} // Constructor using initializer list
private:
int num1, num2, num3;
};

// Creating an object and passing arguments to the constructor using initializer list
MyClass obj({1, 2, 3});

Destructors

A destructor is a special function that gets called automatically when an object of a class goes out of scope or is deleted explicitly. Its primary purpose is to clean up any resources acquired by the object, such as memory allocated dynamically using new.

Default Destructor

When no destructor is explicitly defined in a class, the compiler generates a default destructor that does nothing. This is usually sufficient for simple classes without dynamic memory allocation.

class MyClass {
int* data; // Pointer to dynamically allocated memory
public:
MyClass() : data(new int) {} // Constructor allocates memory using 'new'
~MyClass() { delete data; } // Destructor deallocates memory using 'delete'
};

Virtual Destructors

Inheritance hierarchies may require the use of virtual destructors to ensure proper cleanup when deleting base class pointers that point to derived class objects. This is essential for polymorphic objects with multiple levels of inheritance.

class Base {
public:
virtual ~Base() {} // Virtual destructor in the base class
};

class Derived : public Base {
int* data;
public:
Derived() : Base(), data(new int) {}
~Derived() { delete data; }
};

// Polymorphic objects with multiple levels of inheritance
Base* obj = new Derived(); // Creates a derived object and assigns it to a base class pointer
delete obj; // Calls the virtual destructor in the base class, followed by the destructor in the derived class

Worked Example

Let's create a simple Rectangle class with constructors for initializing the object with different parameters:

#include <iostream>
using namespace std;

class Rectangle {
int width, height;
public:
// Default constructor
Rectangle() : width(0), height(0) {}

// Parameterized constructor for initializing with width and height
Rectangle(int w, int h) : width(w), height(h) {}

// Constructor for initializing the object with the width, height, and area (the area is calculated as width * height)
Rectangle(int w, int h, int area) : width(w), height(h) {
if (area != width * height) {
throw invalid_argument("Invalid area");
}
}

// Calculate and display the area of the rectangle
void calculateArea() const { cout << "Area: " << width * height << endl; }
};

int main() {
Rectangle rect1; // Calls the default constructor (no arguments)
Rectangle rect2(5, 10); // Calls the parameterized constructor (with arguments)
Rectangle rect3(4, 6, 24); // Calls the constructor for initializing with width, height, and area

rect1.calculateArea(); // Output: Area: 0
rect2.calculateArea(); // Output: Area: 50
rect3.calculateArea(); // Output: Area: 24 (since the area was provided)

return 0;
}

Common Mistakes

  • Forgetting to initialize data members in constructors: This can lead to uninitialized variables with undefined values.
  • Not defining destructors for classes that use dynamic memory allocation: Failing to deallocate memory can result in memory leaks.
  • Incorrectly implementing virtual destructors in inheritance hierarchies: This may cause issues during polymorphic deletion of base class pointers pointing to derived class objects.
  • Not understanding the difference between constructors and member functions: Constructors are special functions that get called when an object is created, while member functions can be called on existing objects for various purposes.

Practice Questions

  1. Write a constructor for a Point class that takes x and y coordinates as parameters.
  2. Implement a destructor for the Point class from question 1 to deallocate dynamically allocated memory (if any).
  3. Create a Shape base class with a virtual function calculateArea(). Write a derived Circle class that implements this function and calculates the area using Pi and the radius.
  4. Modify the Rectangle class from the worked example to include a constructor for initializing the object with the width, height, and area (the area is calculated as width * height).

FAQ

  1. Can I return a value from a constructor? No, constructors cannot return values because they are special member functions that get called during object creation. Instead, you should initialize data members within the constructor body.
  2. What happens when an exception is thrown in a constructor? If an exception is thrown during the construction of an object, the object is not created, and any resources allocated by previous constructors are left in an inconsistent state. To avoid this, consider using exception-safe construction techniques such as the "Resource Acquisition Is Initialization" (RAII) pattern.
  3. Can I call one constructor from another within a class? Yes, you can use the initializer list syntax to call one constructor from another within a class. This is known as delegating constructors and allows for more flexible initialization of objects with multiple data members.
  4. What are some common techniques for exception-safe construction? Some common techniques include using the "Resource Acquisition Is Initialization" (RAII) pattern, which ensures that resources are acquired and released in the appropriate destructor, and using the "Exception Specification" mechanism to specify which exceptions a function can throw.
  5. What is constructor chaining, and how does it work? Constructor chaining allows you to call one constructor from another within a class by using the : colon followed by the name of the constructor to be called. This enables more flexible initialization of objects with multiple data members and avoids code duplication.
  6. What is the difference between a constructor and a copy constructor? A constructor is a special function that gets called when an object of a class is created, while a copy constructor is a specific type of constructor that gets called when an object is copied (e.g., during assignment or passing by value). The copy constructor ensures that the new object is properly initialized with a copy of the original object's data members.
  7. What is the difference between a constructor and a move constructor? A constructor is a special function that gets called when an object of a class is created, while a move constructor is a specific type of constructor that gets called when an object is moved (e.g., during rvalue references or std::move). The move constructor ensures that the original object's data members are left in a valid but unspecified state, and the new object is properly initialized with the resources from the original object.
  8. What is the difference between a copy assignment operator and a move assignment operator? The copy assignment operator is a member function that gets called when an object is assigned to another object of the same type (e.g., obj1 = obj2;). The move assignment operator is a specific type of assignment operator that gets called when an object is assigned to another object using rvalue references or std::move (e.g., obj1 = std::move(obj2);). The move assignment operator ensures that the original object's data members are left in a valid but unspecified state, and the new object is properly initialized with the resources from the original object.
  9. What is the purpose of a class's copy constructor, copy assignment operator, move constructor, and move assignment operator? These special member functions ensure that objects are properly initialized and cleaned up during creation, assignment, and destruction. They help manage resources efficiently and avoid common bugs such as memory leaks and data corruption.
  10. What is the difference between a class's default constructor and parameterized constructor? The default constructor is a constructor with no arguments that gets called when an object of a class is created without any arguments (e.g., MyClass obj;). A parameterized constructor is a constructor with one or more arguments that gets called when an object of a class is created with the appropriate arguments (e.g., MyClass obj(10);). The default constructor initializes data members to their default values, while the parameterized constructor initializes data members with the provided arguments.
constructor (C++) | C++ | XQA Learn