Skip to Content
ClassesConstructors

Constructors in C++

A constructor is a special member function that is automatically called when an object of a class is created. It initializes the object’s data members.

What is a Constructor?

A constructor has the same name as the class and no return type (not even void). Its primary purpose is to initialize objects.

Key Characteristics:

  • Same name as the class
  • No return type
  • Automatically called when object is created
  • Can be overloaded
  • Cannot be inherited

Types of Constructors

  1. Default Constructor
  2. Parameterized Constructor
  3. Copy Constructor
  4. Move Constructor (C++11)

1. Default Constructor

A constructor with no parameters:

#include <iostream> using namespace std; class Student { private: string name; int age; public: // Default constructor Student() { name = "Unknown"; age = 0; cout << "Default constructor called" << endl; } void display() { cout << "Name: " << name << ", Age: " << age << endl; } }; int main() { Student s1; // Default constructor is called s1.display(); return 0; }

Output:

Default constructor called Name: Unknown, Age: 0

2. Parameterized Constructor

A constructor that accepts parameters:

#include <iostream> #include <string> using namespace std; class Car { private: string brand; string model; int year; public: // Parameterized constructor Car(string b, string m, int y) { brand = b; model = m; year = y; cout << "Parameterized constructor called" << endl; } void display() { cout << year << " " << brand << " " << model << endl; } }; int main() { Car car1("Toyota", "Camry", 2023); car1.display(); Car car2("Honda", "Civic", 2024); car2.display(); return 0; }

Output:

Parameterized constructor called 2023 Toyota Camry Parameterized constructor called 2024 Honda Civic

Constructor Overloading

You can have multiple constructors with different parameters:

#include <iostream> using namespace std; class Rectangle { private: double length; double width; public: // Default constructor Rectangle() { length = 1.0; width = 1.0; } // Parameterized constructor with one parameter (square) Rectangle(double side) { length = side; width = side; } // Parameterized constructor with two parameters Rectangle(double l, double w) { length = l; width = w; } double getArea() { return length * width; } void display() { cout << "Length: " << length << ", Width: " << width; cout << ", Area: " << getArea() << endl; } }; int main() { Rectangle r1; // Calls default constructor Rectangle r2(5); // Calls single parameter constructor Rectangle r3(4, 6); // Calls two parameter constructor r1.display(); r2.display(); r3.display(); return 0; }

Output:

Length: 1, Width: 1, Area: 1 Length: 5, Width: 5, Area: 25 Length: 4, Width: 6, Area: 24

Member Initializer List

A more efficient way to initialize members:

#include <iostream> #include <string> using namespace std; class Student { private: string name; int rollNumber; double gpa; public: // Using member initializer list Student(string n, int r, double g) : name(n), rollNumber(r), gpa(g) { cout << "Student created using initializer list" << endl; } void display() { cout << "Name: " << name << endl; cout << "Roll: " << rollNumber << endl; cout << "GPA: " << gpa << endl; } }; int main() { Student s1("Alice", 101, 3.9); s1.display(); return 0; }

Output:

Student created using initializer list Name: Alice Roll: 101 GPA: 3.9

3. Copy Constructor

Creates a new object as a copy of an existing object:

#include <iostream> using namespace std; class Point { private: int x, y; public: // Parameterized constructor Point(int xVal, int yVal) : x(xVal), y(yVal) { cout << "Parameterized constructor called" << endl; } // Copy constructor Point(const Point& p) { x = p.x; y = p.y; cout << "Copy constructor called" << endl; } void display() { cout << "Point(" << x << ", " << y << ")" << endl; } }; int main() { Point p1(10, 20); p1.display(); Point p2 = p1; // Copy constructor is called p2.display(); Point p3(p1); // Another way to call copy constructor p3.display(); return 0; }

Output:

Parameterized constructor called Point(10, 20) Copy constructor called Point(10, 20) Copy constructor called Point(10, 20)

Deep Copy vs Shallow Copy

Shallow Copy (Default behavior)

class Array { private: int* data; int size; public: Array(int s) : size(s) { data = new int[size]; } // If no copy constructor is defined, // shallow copy happens (both objects point to same memory) };

Deep Copy (Proper way)

#include <iostream> using namespace std; class Array { private: int* data; int size; public: // Constructor Array(int s) : size(s) { data = new int[size]; for (int i = 0; i < size; i++) { data[i] = i; } } // Deep copy constructor Array(const Array& other) : size(other.size) { data = new int[size]; // Allocate new memory for (int i = 0; i < size; i++) { data[i] = other.data[i]; // Copy values } cout << "Deep copy created" << endl; } // Destructor ~Array() { delete[] data; } void display() { cout << "Array: "; for (int i = 0; i < size; i++) { cout << data[i] << " "; } cout << endl; } }; int main() { Array arr1(5); arr1.display(); Array arr2 = arr1; // Deep copy arr2.display(); return 0; }

Output:

Array: 0 1 2 3 4 Deep copy created Array: 0 1 2 3 4

Default Arguments in Constructors

#include <iostream> using namespace std; class Book { private: string title; string author; int pages; public: // Constructor with default arguments Book(string t = "Unknown", string a = "Unknown", int p = 0) : title(t), author(a), pages(p) {} void display() { cout << "Title: " << title << endl; cout << "Author: " << author << endl; cout << "Pages: " << pages << endl << endl; } }; int main() { Book b1; // All defaults Book b2("1984"); // Partial defaults Book b3("Animal Farm", "George Orwell"); // Partial defaults Book b4("The Hobbit", "J.R.R. Tolkien", 310); // No defaults b1.display(); b2.display(); b3.display(); b4.display(); return 0; }

Output:

Title: Unknown Author: Unknown Pages: 0 Title: 1984 Author: Unknown Pages: 0 Title: Animal Farm Author: George Orwell Pages: 0 Title: The Hobbit Author: J.R.R. Tolkien Pages: 310

Explicit Constructor

Prevents implicit type conversions:

#include <iostream> using namespace std; class Integer { private: int value; public: // Explicit constructor explicit Integer(int v) : value(v) {} void display() { cout << "Value: " << value << endl; } }; int main() { Integer i1(10); // OK // Integer i2 = 20; // Error: implicit conversion not allowed i1.display(); return 0; }

Delegating Constructors (C++11)

One constructor can call another:

#include <iostream> using namespace std; class Box { private: double length, width, height; public: // Main constructor Box(double l, double w, double h) : length(l), width(w), height(h) { cout << "Main constructor called" << endl; } // Delegating constructors Box() : Box(1, 1, 1) { cout << "Default constructor delegates to main" << endl; } Box(double side) : Box(side, side, side) { cout << "Cube constructor delegates to main" << endl; } double getVolume() { return length * width * height; } }; int main() { Box b1; cout << "Volume: " << b1.getVolume() << endl << endl; Box b2(5); cout << "Volume: " << b2.getVolume() << endl; return 0; }

Output:

Main constructor called Default constructor delegates to main Volume: 1 Main constructor called Cube constructor delegates to main Volume: 125

Constructor Best Practices

  1. Always initialize all members: Uninitialized data can cause bugs
  2. Use initializer lists: More efficient than assignment in body
  3. Make single-argument constructors explicit: Prevents unwanted conversions
  4. Provide default constructor when needed
  5. Implement copy constructor for classes with dynamic memory
  6. Use const references for copy constructor parameters

Common Mistakes

1. Missing Initialization

// Wrong class MyClass { int* ptr; public: MyClass() {} // ptr is uninitialized! }; // Correct class MyClass { int* ptr; public: MyClass() : ptr(nullptr) {} };

2. Calling Constructor Explicitly

// Wrong MyClass obj; obj.MyClass(); // Error: Can't call constructor like this // Correct MyClass obj; // Constructor is called automatically

Practice Exercises

  1. Bank Account: Create a class with constructor to initialize account number, name, and balance

  2. Date Class: Implement a Date class with constructors for different date formats

  3. Matrix: Create a Matrix class with constructors for different initializations

  4. String Class: Implement your own String class with proper copy constructor

  5. Complex Number: Create a Complex class with multiple constructors for different representations

Constructors are essential for proper object initialization in C++!

Last updated on