Constructors in C++

mycplus

mycplus

What is a Constructor?

A constructor is a special method that is created when the object is created or defined. This particular method holds the same name as that of the object and it initializes the instance of the object whenever that object is created. The constructor also usually holds the initialization of the different declared member variables of its object. Unlike some of the other methods, the constructor does not return a value, not even void.

A constructor is declared without a return value, that also excludes void. Therefore, when when implemented, do not return a value:

Constructor Example in C++

class rectangle {              // A simple class
   int height;
   int width;
public:
   rectangle(void);            // with a constuctor,
   ~rectangle(void);           // and a destructor
};

rectangle::rectangle(void)     // constuctor
{
   height = 6;
   width = 6;
}

Default Constructor

When you create an object, if you do not declare a constructor, the compiler would create one for your program; this is useful because it lets all other objects and functions of the program know that this object exists. This compiler created constructor is called the default constructor. If you want to declare your own constructor, simply add a method with the same name as the object in the public section of the object. When you declare an instance of an object, whether you use that object or not, a constructor for the object is created and signals itself.

#include <iostream>
using namespace std;

struct TBook
{
public:
    TBook();    // Constructor
};

TBook::TBook()
{
    cout << "I see a book...\n";
}

int main()
{
    TBook B;

    return 0;
}

This would produce:

I see a book...

This book constructor is a programmer created constructor and is empty. You might find it sometimes convenient to create your own constructor because, whether you create an empty constructor or not, this does not negatively impact your program but makes it more lively and allows other parts of the program to conveniently call the object using its constructor. A constructor is easily implemented once you have created one:

There are various categories of bricks used in the construction industry.

For this exercise, we will consider a simple one used in constructing domestic building foundations. It has a total length, here called Length; it also has a height, referred here to as Height; and it has a thickness that will be called Thickness. For resistance and static reasons, our brick will have two holes. Since we are more interested in the amount of cement used to create the brick, we will subtract the volume of the hole from the total volume. The dimensions we use are for simplicity. We will consider that the small wall of the brick has a thickness of 0.25; also, the static wall in the middle length has a thickness of 0.25.

Listing – Brick Unit – Header File: Bricks.h. The header file uses #ifndef and #define directives to define the class.

#ifndef BricksH
#define BricksH

struct TBrick
{
public:
     TBrick(); // Empty Constructor
    void  setDimensions(double l, double h, double t);
    void  Initializer(double l, double h, double w);
    double  CementVolume();
    void  ShowProperties();
private:
    double Length;
    double Height;
    double Thickness;
};

#endif

Brick Unit – Source File: Bricks.cpp

#include <iostream>
using namespace std;

#include "Bricks.h"

TBrick::TBrick()
{
    //TODO: Add your source code here
}

void  TBrick::setDimensions(double l, double h, double t)
{
    Length = l;
    Height = h;
    Thickness = t;
}

double  TBrick::CementVolume()
{
    double Enclosure = 0.50; // This includes both walls of the brick itself
    double HoleLength = Length - 0.75; // Including both holes
    double HoleThickness = Thickness - Enclosure;
    double HoleVolume = HoleLength * HoleThickness * Height;
    double TotalVolume = Length * Height * Thickness;
    double ValidVolume = TotalVolume - HoleVolume;

    return ValidVolume;
}

void  TBrick::ShowProperties()
{
    cout << "Foundation Brick Properties";
    cout << setiosflags(ios::fixed) << setprecision(2);
    cout << "\nLength    = " << Length; cout
         << "\nHeight    = " << Height;
    cout << "\nThickness = " << Thickness;
    cout << "\nCement Volume = " << CementVolume() << "\n";
}

Main File: Main.cpp

#include <iostream>
using namespace std;
#include "Bricks.h"

int main()
{
    TBrick Foundation;

    Foundation.setDimensions(4.24, 3.55, 3.45);
    Foundation.ShowProperties();

    return 0;
}

This program would produce:

Foundation Brick Properties
Length    = 4.24
Height    = 3.55
Thickness = 3.45
Cement Volume = 15.38

Press any key to continue...

Initializing a constructor

A constructor does not exist simply for cosmetic reasons in C++ versions. It can be used to initialize the member variables of an object. Therefore, a constructor provides a valuable alternative to a method initializer, the type of method we saw earlier.

To use a constructor to initialize the member variables of an object, provide as arguments the necessary variables that you intend to initialize. You do not have to initialize all member variables in the constructor, only those that need to be initialized. In fact, you should initialize only those members that you think the other objects or functions would need to provide when calling this object; this means that your object may have member variables that, either the external objects or functions do not need to modify (or access) or the member variable will be initialized later when called from the needed object or function. To initialize the members of our Brick object, its method constructor would be declared as in the following file:

Listing – Brick Unit – Header File: Bricks.h

#ifndef BricksH
#define BricksH

struct TBrick
{
public:
     TBrick();    // Default Constructor
     TBrick(double l, double h, double t);
    double  CementVolume();
    void  ShowProperties();
private:
    double Length;
    double Height;
    double Thickness;
};
#endif

Listing – Brick Unit – Source File: Bricks.cpp

#include <iostream>

using namespace std;
#include "Bricks.h"

 TBrick::TBrick()
{
    //TODO: Add your source code here
}

 TBrick::TBrick(double l, double h, double t)
{
    Length = l;
    Height = h;
    Thickness = t;
}

double  TBrick::CementVolume()
{
    double Enclosure = 0.50; // This includes both walls of the brick itself
    double HoleLength = Length - 0.75; // Including both holes
    double HoleThickness = Thickness - Enclosure;
    double HoleVolume = HoleLength * HoleThickness * Height;
    double TotalVolume = Length * Height * Thickness;
    double ValidVolume = TotalVolume - HoleVolume;

    return ValidVolume;
}

void  TBrick::ShowProperties()
{
    cout << "Foundation Brick Properties";
    cout << setiosflags(ios::fixed) << setprecision(2);
    cout << "\nLength    = " << Length; cout
         << "\nHeight    = " << Height;
    cout << "\nThickness = " << Thickness;
    cout << "\nCement Volume = " << CementVolume() << "\n";
}

Main File: Main.cpp

#include <iostream>
using namespace std;
#include "Bricks.h"

int main()
{
    TBrick Solid(4.15, 3.35, 3.05);
    Solid.ShowProperties();

    return 0;
}

This would produce the following result:

Foundation Brick Properties
Length    = 4.15
Height    = 3.35
Thickness = 3.05
Cement Volume = 13.36

Press any key to continue...

To safeguard and protect the member variables of an object, we have learned to use set and get methods. If you use set methods to protect the variables of an object, you can conveniently call these methods from the constructor to initialize those member variables. Therefore, a constructor can also be used to call methods that hold the initial values of member variables.

C++ Constructor Overloading

Like an ordinary method overloading or operator overloading, a construction can be overloaded. This means that you can have different constructors following the rules of overloading a function. Since we saw that a constructor can be used to initialize the member variables of its object, you can use multiple constructors to apply different initializations.

If you declare a constructor as

TBrick Foundation;

you can use it to call other method members of the same object. The problem is that if you just try to call a method that displays the values of the member variables, you will get bizarre and unpredictable results. Consider the TBrick object created as

struct TBrick
{
public:
     TBrick();
    double  CementVolume();
    void  ShowProperties();
private:
    double Length;
    double Height;
    double Thickness;
};

And implemented as

#include <iostream>
using namespace std;

#include "Bricks.h"

 TBrick::TBrick()
{
    //TODO: Add your source code here
}
double  TBrick::CementVolume()
{
    double Enclosure = 0.50; // This includes both walls of the brick itself
    double HoleLength = Length - 0.75; // Including both holes double
    double HoleThickness = Thickness - Enclosure;
    double HoleVolume = HoleLength * HoleThickness * Height;
    double TotalVolume = Length * Height * Thickness;
    double ValidVolume = TotalVolume - HoleVolume;

    return ValidVolume;
}
void  TBrick::ShowProperties()
{
    cout << "Foundation Brick Properties";
    cout << "\nLength = " << Length;
    cout << "\nHeight = " << Height;
    cout << "\nThickness = " << Thickness;
    cout << "\nCement Volume = " << CementVolume() << "\n";
}

If you declare the TBrick object using the default constructor, and decide to call a method that displays the variables values, you could write it like this:

#include <iostream>
using namespace std;
#include "Bricks.h"

int main()
{
    TBrick Mango;

    Mango.ShowProperties();

    return 0;
}

This would produce the following result:

Foundation Brick Properties
Length = nan
Height = 2.53988e-314
Thickness = 2.122e-314
Cement Volume = nan

Press any key to continue...

As you can see, these values do not make sense to us.

To make sure that a calling function does not have to supply values for the member variables, you can also use the empty constructor to supply default values to these variables. If you simply use the default constructor to get the values of the member variables, the object would use the values given in the empty constructor and perform all necessary operations:

 TBrick::TBrick()
{
    Length = 4.15;
    Height = 3.55;
    Thickness = 3.75;
}

This time, the same program would produce a sound result:

Foundation Brick Properties
Length = 4.15
Height = 3.55
Thickness = 3.75
Cement Volume = 16.0194

Press any key to continue...

This technique of using the default constructor allows you to conveniently supply default values for the member variables. As flexible as this is, you can use a certain constructor to initialize just one of the member variables and supply default values for the others. When constructing a brick, one of the dimensions would be of primary importance because it influences what the brick is used for. On this exercise, let’s allow a calling function to supply the length of the brick while we control the other two dimensions. We can declare more than one constructor in the header file:

Brick Unit – Header File: Brick.h

#ifndef BricksH
#define BricksH

class TBrick
{
public:
     TBrick();
    <strong> TBrick(double L);</strong>
    double  CementVolume();
    void  ShowProperties();
private:
    double Length;
    double Height;
    double Thickness;
};
#endif

Brick Unit – Source File: Brick.cpp

#include <iostream>
using namespace std;

#include "Bricks.h"

 TBrick::TBrick()
{
    Length = 4.15;
    Height = 3.55;
    Thickness = 3.75;
}
TBrick::TBrick(double L)
{
    Length = L;
    Height = 5.25;
    Thickness = 4.55;
}

double  TBrick::CementVolume()
{
    ...
}
//---
void  TBrick::ShowProperties()
{
    ...
}
//---

Since this constructor takes one argument, when declaring an object that would use this constructor, assign only one value to the argument variable. Such a value is provided in the parentheses allocated to the instance of the object. Here is an example:

Main File: Main.cpp

#include <iostream>
using namespace std;
#include "Bricks.h"

int main()
{
    // Brick with default dimensions
    TBrick Mather;
    Mather.ShowProperties();
    cout << endl;

    // Brick with a supplied length
    TBrick BedTimer(5.55);
    BedTimer.ShowProperties();

    return 0;
}

This would produce the following result:

Foundation Brick Properties
Length = 4.15
Height = 3.55
Thickness = 3.75
Cement Volume = 16.0194

Foundation Brick Properties
Length = 5.55
Height = 5.25
Thickness = 4.55
Cement Volume = 30.5156

Press any key to continue...

If you declare different constructors with different arguments to initialize (remember the rules of function overloading), when declaring these objects, make sure you initialize each instance with the right number of arguments; otherwise, the compiler would complain.

Here is our program that makes use of three constructors, each with different arguments:

Brick Unit – Header File: Brick.h

#ifndef BricksH
#define BricksH

class TBrick
{
public:
     TBrick();
     TBrick(double L);
    <strong> TBrick(double L, double h, double t);</strong>
    double  CementVolume();
    void  ShowProperties();
private:
    double Length;
    double Height;
    double Thickness;
};

#endif

The new constructor can be implemented as follows:

TBrick::TBrick(double L, double h, double t)
{
    Length = L;
    Height = h;
    Thickness = t;
}

Main File: Main.cpp

#include <iostream>
using namespace std;
#include "Bricks.h"

int main()
{
    // Brick with default dimensions
    TBrick GrayMatte;
    GrayMatte.ShowProperties();
    cout << endl;

    // Brick with a supplied length
    TBrick OldTimer(5.55);
    OldTimer.ShowProperties();
    cout << endl;

    // A Brick with set dimensions
    TBrick Fantasma(3.25, 3.05, 3.25);
    Fantasma.ShowProperties();

    return 0;
}

This would produce:

Foundation Brick Properties
Length = 4.15
Height = 3.55
Thickness = 3.75
Cement Volume = 16.0194

Foundation Brick Properties
Length = 5.55
Height = 5.25
Thickness = 4.55
Cement Volume = 30.5156

Foundation Brick Properties
Length = 3.25
Height = 3.05
Thickness = 3.25
Cement Volume = 11.2469

Press any key to continue...

If you create an object and create it with only one constructor, if you create this constructor with at least one argument, the default constructor would not be available anymore. For example if you create a TBrick object as follows:

#ifndef BricksH
#define BricksH

class TBrick
{
public:
    <strong> TBrick(double L, double h, double t);</strong>
    double  CementVolume();
    void  ShowProperties();
private:
    double Length;
    double Height;
    double Thickness;
};

#endif

and implement the TBrick(double L, double h, double t) constructor as we saw above, the following main() function would halt the program:

#include <iostream>
using namespace std;
#include "Bricks.h"

int main()
{
    // The following (default) constructor is not available
    <strong>TBrick GrayMatte;</strong>
    GrayMatte.ShowProperties();
    cout << endl;

    // A Brick with set dimensions
    TBrick Fantasma(3.25, 3.05, 3.25);
    Fantasma.ShowProperties();

    return 0;
}

Accessing default Constructor of an object in C++

Therefore, if you want to access a default constructor of an object in C++, you have two alternatives:

  • If you don’t create any constructor at all on an object, the default constructor would always be available whenever you invoke that object.
  • If you create at least one constructor on an object and supply at least one argument to that constructor, you must explicitly create a default constructor for your object.

Based on what we have learned already, here is our complete program with set and get methods.

Brick Unit – Header File: Brick.h

#ifndef BricksH
#define BricksH

class TBrick
{
public:
     TBrick();
     TBrick(double L);
     TBrick(double L, double h, double t);
    double  getLength() const;
    void  setLength(const double l);
    double  getHeight() const;
    void  setHeight(const double h);
    double  getThickness() const;
    void  setThickness(const double t);
    double  CementVolume();
    void  ShowProperties();
private:
    double Length;
    double Height;
    double Thickness;
};
#endif

Brick Unit – Source File: Brick.cpp

#include <iostream>
using namespace std;

#include "Bricks.h"

 TBrick::TBrick()
{
    Length = 4.15;
    Height = 3.55;
    Thickness = 3.75;
}
TBrick::TBrick(double L)
{
    Length = L;
    Height = 5.25;
    Thickness = 4.55;
}
TBrick::TBrick(double L, double h, double t)
{
    Length = L;
    Height = h;
    Thickness = t;
}
double  TBrick::getLength() const
{
    return Length;
}

void  TBrick::setLength(const double l)
{
    Length = l;
}

double  TBrick::getHeight() const
{
    return Height;
}

void  TBrick::setHeight(const double h)
{
    Height = h;
}

double  TBrick::getThickness() const
{
    return Thickness;
}

void  TBrick::setThickness(const double t)
{
    Thickness = t;
}

double  TBrick::CementVolume()
{
    double Enclosure = 0.50; // This includes both walls of the brick itself
    double HoleLength = Length - 0.75; // Including both holes double
    double HoleThickness = Thickness - Enclosure;
    double HoleVolume = HoleLength * HoleThickness * Height;
    double TotalVolume = Length * Height * Thickness;
    double ValidVolume = TotalVolume - HoleVolume;

    return ValidVolume;
}

void  TBrick::ShowProperties()
{
    cout << "Foundation Brick Properties";
    cout << setiosflags(ios::fixed) << setprecision(2);
    cout << "\nLength = " << Length;
    cout << "\nHeight = " << Height;
    cout << "\nThickness = " << Thickness;
    cout << "\nCement Volume = " << CementVolume() << "\n";
}

Main File: Main.cpp

#include <iostream>
using namespace std;
#include "Bricks.h"

int main()
{
    // Brick with default dimensions
    TBrick GrayMatte;
    GrayMatte.ShowProperties();
    cout << endl;

    // Brick with a supplied length
    TBrick OldTimer(5.55);
    OldTimer.ShowProperties();
    cout << endl;

    // A Brick with user supplied dimensions
    double len, hgt, thk;
    cout << "\nEnter the dimensions of the brick\n";
    cout << "Length: ";
    cin >> len;
    cout << "Height: ";
    cin >> hgt;
    cout << "Thickness: ";
    cin >> thk;
    cout << endl;
    TBrick Fantasma(len, hgt, thk);
    Fantasma.ShowProperties();

    return 0;
}

Here is an example of running the program:

Foundation Brick Properties
Length = 4.15
Height = 3.55
Thickness = 3.75
Cement Volume = 16.02

Foundation Brick Properties
Length = 5.55
Height = 5.25
Thickness = 4.55
Cement Volume = 30.52

Enter the dimensions of the brick
Length: 6.25
Height: 5.85
Thickness: 4.55

Foundation Brick Properties
Length = 6.25
Height = 5.85
Thickness = 4.55
Cement Volume = 36.05

Press any key to continue...
M. Saqib: Saqib is Master-level Senior Software Engineer with over 14 years of experience in designing and developing large-scale software and web applications. He has more than eight years experience of leading software development teams. Saqib provides consultancy to develop software systems and web services for Fortune 500 companies. He has hands-on experience in C/C++ Java, JavaScript, PHP and .NET Technologies. Saqib owns and write contents on mycplus.com since 2004.
Related Post