A Deep Dive into Constructors and Destructors

Eunchong JungEunchong Jung
5 min read

C++ is a multiparadigm, highly-efficient, general-purpose programming language still viable in the modern programming world up to this point. This post will specifically cover two of the fundamental aspects of C++ which are Constructors and Destructors.

What are Constructors and Destructors?

Before talking about Constructors and Destructors, a C++ Class must first be covered. In C++ a class is a custom datatype that associates specific functionalities with data. The access parameter is specified by three types: private, protected, or public.

Constructors and Destructors are member functions of a class associated with the construction and destruction of objects in a class. They both have the same names as the class without a return type.

Constructors

Constructors are called when an instance of a class is created. They help initialize the object of a class by allocating the memory to an object of the class. It can be created multiple times in a class and can be overloaded, but cannot be inherited or virtual.

The following is an example of a constructor.

class MyClass {
  public:
    int x;
    MyClass() {   // Constructor
      x = 10;
    }
};

int main() {
  MyClass obj;
  std::cout << obj.x;
  return 0;
}

In this example, when an object of MyClass class is instantiated (obj), the constructor MyClass() is called. This initializes the value of x to 10, outputting the value 10 in the main function.

Destructors

Destructor is also a special type of member function executed when an object's lifetime ends. It deallocates the memory associated with an object and contains the same class name preceded by a ~ operator. It can only be called after a constructor. If an inheriting class and the parent class both contain destructors, child class destructors are called first, followed by the parent class destructors.

The following is an example of a destructor

class MyClass {
  public:
    MyClass() {   // Constructor
      std::cout << "Constructor Called\n";
    }
    ~MyClass() {  // Destructor
      std::cout << "Destructor Called\n";
    }
};

int main() {
  MyClass obj;
  return 0;
}

In this example, when the main function executes completely, obj object goes out of scope. This calls the destructor of its class, outputting "Destructor Called" in the end.

Types of Constructors

Constructor types vary depending on the functions and parameters. There are three types of constructors in C++:

  1. Default Constructor: Constructor without parameters.

  2. Parameterized Constructor: Constructor with parameters.

  3. Copy Constructor: Constructor that initializes an object using another object of the same class.

Why Constructors and Destructors?

Objects are the most essential element of Object Oriented Programming. Constructors help initialize class object members that can be aspects of other classes, arrays, or structures that require initialization before a class object can be used. On the other hand, destructors are essential to do a cleanup for a class object and its class members when the object is destroyed.

Virtual Constructors and Destructors

In C++ we cannot make constructors virtual. This is because virtual functions usually refer to a derived method, while constructors are invoked at the very first when an object is created. Therefore, when a constructor is invoked, there are no virtual methods. Only after the constructor runs, a virtual table is constructed to invoke a virtual method. If you force yourself to write a virtual constructor as below, the compiler will return a "fpermissive" error.

class Base {
public:
    virtual Base() { std::cout << "Base Constructor\n"; }
    ~Base() { std::cout << "Base Destructor\n"; }
};

int main() {
    Base *b = new Derived();
    delete b;
    return 0;
}
error: constructors cannot be declared 'virtual' [-fpermissive]

On the other hand, we can create a virtual destructor. A virtual destructor is used for appropriate resource management, especially in the situation of inheritance. If a class has a base class with a virtual destructor, the class destructor will also be virtual. This means that when the derived object with a base class containing a virtual destructor is deleted, the destructor of the corresponding derived class is called. See the example code below.

class Base {
public:
    Base() { std::cout << "Base Constructor\n"; }
    virtual ~Base() { std::cout << "Base Destructor\n"; }
};

class Derived : public Base {
public:
    Derived() { std::cout << "Derived Constructor\n"; }
    ~Derived() { std::cout << "Derived Destructor\n"; }
};

int main() {
    Base *b = new Derived();
    delete b;
    return 0;
}
Base Constructor
Derived Constructor
Derived Destructor
Base Destructor

Copy Constructors

A copy constructor is a constructor that creates an object by initializing it with an object of the same class. It is useful for initializing new objects by copying the members of an existing object. Even if we don't define it, C++ will assign a default copy constructor that does a member-wise copy between objects.

class MyClass {
public:
    int x;
    // Copy constructor
    MyClass(const MyClass &obj) {
        x = obj.x;
        std::cout << "Copy constructor called\n";
    }
};

int main() {
    MyClass a; 
    a.x = 10;

    MyClass b = a;  // Copy constructor is called here
    std::cout << b.x;

    return 0;
}

Here, when object b is initialized and assigned with a previously created object a, the copy constructor is called, enabling b to contain the same value of x as object a.

Copy constructor called
10

Assignment Operators

Unlike copy constructors, we can overload assignment operators to copy the values of one object to another existing object. Therefore, assignment operators are called when an already initialized object is assigned a new value from another object.

class MyClass {
public:
    int x;

    // Parameterized Constructor
    MyClass(int val) : x(val) {}

    // Overloaded Assignment Operator
    MyClass& operator=(const MyClass &obj) {
        x = obj.x;
        std::cout << "Assignment operator called\n";
        return *this;
    }
};

int main() {
    MyClass a(10);
    MyClass b = a; // Copy constructor is called here, not the assignment operator
    MyClass c(0);
    c = a;  // Assignment operator is called here

    std::cout << c.x;
    return 0;
}

In this example, an overloaded assignment operator is created in MyClass class. Keep in mind that C++ will create a default assignment operator if it is not created which does member-wise assignment. In the main function, when an existing object c is assigned values of another object a, the assignment operator is invoked, returning the value pointed by this pointer.

Assignment operator called
10
0
Subscribe to my newsletter

Read articles from Eunchong Jung directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Eunchong Jung
Eunchong Jung

I am an Associate Developer at SAP. I'd like to grasp deeper into the C++ programming language, and I hope that you join my journey of learning with my posts.