Constructors in C++

Rishabh Agarwal
Towards Dev
Published in
6 min readFeb 12, 2023

--

Photo by Olga Nayda on Unsplash

In this article, we will be understanding Constructors and Destructors in C++. We will be going through some code examples to understand these concepts better.

Interested in learning more C++ programming constructs? Check out other blogs in this series -

Let us understand some nomenclatures before we understand C++ constructors.

Nomenclature

  • Constructor is a method for a class that gets called automatically whenever an object of that class is created. It is a good place to initialise data members.
  • Destructor is a method for a class that gets called automatically whenever an object of that class is destroyed. It is a good place to delete any dynamically allocated memory in the application.
  • Default Constructor is a constructor with no parameters. Such constructors initialise data members with some default values. When an array of class objects is created, the default constructor is always invoked for each element.
  • Initialising Constructor is a constructor that takes a set of parameters used to initialise class’s data members.
  • Copy Constructor is a constructor that takes another object of the same class as its reference parameter, and makes the new object an exact copy of the argument.
  • Static Member is a member variable of a given class that is shared by all objects of that class, instead of being unique to a particular object.

Constructors

A constructor is a method that is automatically called whenever an object of that class is created. Its name is always the same as that of the class and it does not have a return type (not even void). A default constructor takes no argument whereas an Initialising or Copy constructors have arguments.

class Point {
private:
int x, y;
public:
Point(); // Default Constructor
Point(int x0, int y0); // Initialising Constructor
Point(const Point &pt); // Copy Constructor
}

Here is how these constructors can be defined.

Point::Point() {
x = 0;
y = 0;
}

Point::Point(int x0, int y0) {
x = x0;
y = y0;
}
Point::Point(const Point &pt) {
x = pt.x;
y = pt.y;
}

Destructors

A destructor is a method of a class that is automatically called whenever object of that class is deleted. Its name is always the class name preceded by a ~, it takes no parameters, and there is no return value (not even void).

class Point {
private:
int x, y;
public:
Point();
~Point(); // Destructor
}

Here is how a destructor can be defined.

Point::~Point() {
// Write your logic here
}

Initialisation List

For Default and Initialising Constructors, a better way of doing member variable initialisation is with an initialisation list in the constructor definition.

Point::Point(): x(0), y(0) {}
Point::Point(int x0, int y0): x(x0), y(y0) {}

Constructor Usages

A constructor is called every-time an object of that class is created. Here are some examples -

Point p0; // Default constructor is called, coordinates (0, 0)
Point p1(10, 50); // Initialsing constructor is called, coordinates (10, 50)
Point plist[20]; // Default constructor is called for each element, each coordinate is (0, 0)
Point p2(p1); // Copy constructor, coordinates (10, 50)
Point *pt0 = new Point; // Default constructor, *pt0 coordinates (0, 0)
Point *pt1 = new Point(10, 50); // Initialising constructor, *pt1 coordinates (10, 50)
Point *pt2 = new Point(*pt1); // Copy constructor, *pt2 coordinates (10, 50)

Default Parameters

Any function or method in C++ can be defined with default parameters. A default argument is a value provided in a function declaration that is automatically assigned by the compiler if the calling function doesn’t provide a value for the argument. In case any value is passed, the default value is overridden.

Using default parameters we can write this single code for both the default constructor and initialising constructor.

Point::Point(int x0=0, int y0=0): x(x0), y(y0) {}

This declaration simulates the default constructor, since x0 and y0 are not supplied, x and y take on their default value (0, 0).

Point p0;

This declaration simulates the initialising constructor, since x0 and y0 are supplied, x and y take on the values (10, 50).

Point p1(10, 50);

This declaration is odd but it works. x0 is supplied, but not y0, therefore x and y take on the values (10, 0).

Point p2(10);

As a general rule, while defining a function/method default parameters should be listed towards the end. This is to eliminate ambiguity.

Now that we understand the fundamentals, let’s apply our knowledge to an example.

We will be creating two different classes called Point and Polygon. We will be using concepts that we discussed until now.

Point class

Following will be the definition of the point class. Store this in a file named Point.hpp.

class Point {
private:
int x, y;
public:
Point(int x0 = 0, int y0 = 0);
Point(const Point &pt); // Copy Constructor
void print();
void set(int x0, int y0);
};

Next we will write a definition for the Point class. Store this in a file names Point.cpp.

#include "Point.hpp"
#include <iostream>

Point::Point(int x0 = 0, int y0 = 0): x(x0), y(y0) {}
Point::Point(const Point &pt) {
x = pt.x;
y = pt.y;
}
void Point::print() {
std::cout<<"x = "<<x<<" y = "<<y<<std::endl;
}
void Point::set(int x0, int y0) {
x = x0;
y = y0;
}

This completes the setup for the Point class.

Polygon class

Following will be the definition of the Polygon class. Store this in a file named Polygon.hpp.

#include "Point.hpp"
class Polygon {
private:
static int numpolygons; // Variable to store the number of polygons created
Point *vertices; // Vertices of the polygon
int nverts; // Number of vertices in the polygon
public:
Polygon();
Polygon(const Polygon& poly);
~Polygon();
int getnumpolygons() const; // const means that no data member are modified in this method, check for compiler
void addvertex(const Point &pt);
int getnverts() const;
Point *getvertices() const;
void setvertices(int n, Point *verts);
void print() const;
};

Next we will be write definition for functions we wrote above.

We set the static variable to zero.

int Polygon::numpolygons = 0;

We next create constructors.

Polygon::Polygon(): vertices(NULL), nverts(0){
numpolygons++;
}

Polygon::Polygon(const Polygon &poly){
nverts = poly.nverts;
vertices = new Point[nverts];
for(int i = 0; i < nverts; i++)
vertices[i] = poly.vertices[i];
numpolygons++;
}

Then we create the destructor. Here we will delete the memory allocated for vertex array.

Polygon::~Polygon(){
delete []vertices;
numpolygons--;
}

Next we define some get methods.

int Polygon::getnverts() const{
return nverts;
}
int Polygon::getnumpolygons() const{
return numpolygons;
}
Point *Polygon::getvertices() const{
Point *vtxcopy = new Point[nverts];
for(int i = 0; i < nverts; i++)
vtxcopy[i] = vertices[i];
return vtxcopy;
}

We then define set of methods remaining.

void Polygon::addvertex(const Point &pt){
Point *oldverts = vertices;
vertices = new Point[++nverts];
for(int i = 0; i < nverts - 1; i++)
vertices[i] = oldverts[i];
vertices[nverts - 1] = pt;
delete []oldverts;
}
void Polygon::setvertices(int n, Point *verts){
if(n != nverts){
delete []vertices;
nverts = n;
vertices = new Point[nverts];
}
for(int i = 0; i < nverts; i++)
vertices[i] = verts[i];
}

All in all, you should have a Polygon class, in a file named Polygon.cpp, as follows.

#include "Polygon.hpp"
#include <iostream>

int Polygon::numpolygons = 0;
Polygon::Polygon(): vertices(NULL), nverts(0){
numpolygons++;
}
Polygon::Polygon(const Polygon &poly){
nverts = poly.nverts;
vertices = new Point[nverts];
for(int i = 0; i < nverts; i++)
vertices[i] = poly.vertices[i];
numpolygons++;
}
void Polygon::addvertex(const Point &pt){
Point *oldverts = vertices;
vertices = new Point[++nverts];
for(int i = 0; i < nverts - 1; i++)
vertices[i] = oldverts[i];
vertices[nverts - 1] = pt;
delete []oldverts;
}
Point *Polygon::getvertices() const{
Point *vtxcopy = new Point[nverts];
for(int i = 0; i < nverts; i++)
vtxcopy[i] = vertices[i];
return vtxcopy;
}
void Polygon::setvertices(int n, Point *verts){
if(n != nverts){
delete []vertices;
nverts = n;
vertices = new Point[nverts];
}
for(int i = 0; i < nverts; i++)
vertices[i] = verts[i];
}
void Polygon::print() const{
for(int i = 0; i < nverts - 1; i++){
vertices[i].print();
std::cout << ", ";
}
vertices[nverts - 1].print();
std::cout << std::endl;
}
Polygon::~Polygon(){
delete []vertices;
numpolygons--;
}
int Polygon::getnverts() const{
return nverts;
}
int Polygon::getnumpolygons() const{
return numpolygons;
}

This completes the example.

We have discussed the fundamentals of Constructors and Destructors in C++. We also looked at how to use Initialisation List, Default Parameters and how to apply them to create different classes. We have gone through a complete example of creating a Point and Polygon class. Now that we understand the concepts, we can go ahead and create other classes with ease.

If you liked this article, please consider taking the time to follow me on Twitter and Medium to stay up-to-date with all the new and exciting articles I post. Additionally, if you are looking for more interesting topics, my other articles are sure to capture your attention.

--

--

Software Engineer | Loves to write about Programming, Technology, and Mathematics!