Constructors

explains the idea of constructors in c++. A compiler guarantees the initialization of an object, and even creates constructors when needed

Last Reviewed and Updated on February 7, 2020
Posted by Parveen(Hoven),
Aptitude Trainer and Software Developer

My C/C++ Videos on Youtube

Here is the complete playlist for video lectures and tutorials for the absolute beginners. The language has been kept simple so that anybody can easily understand them. I have avoided complex jargon in these videos.

In this tutorial we shall take up a very important concept of C++ - the constructor.

Constructors in Real Life

To me it appears that C++ has obtained most concepts from the nature around us. It is inspired by the way real life things behave, and how the real life things do work for us. Any gadget or a machine needs some sort of seeding before it can begin to do job for us. A car needs petrol or diesel, a mobile phone needs a formatted phone memory or a formatted memory card. These things just don't work without being given an initial start. They refuse to work at all - they do not start doing weird things in the absence of these inputs, for example, a mobile phone with an un-formatted memory doesn't start calling on wrong phone numbers, or an empty car doesn't start eating it's own engine oil. There is a guarantee that if and when these things work, they work perfectly; and when they cannot deliver, they refuse to start, and force the owner to provide their initialization. So the rule is: An object doesn't work unless it has all the required initializations.

If you see the following class you will see that it is a perfect case of anarchy. It is supposed to print the square of a number supplied by the user, but the user forgot to provide an initial value, by calling the function SetI, and yet the class object proceeds to print a random output - similar to a phone making calls to random phone numbers.

class CCalc
{
private:
    int i;
 
public:
    void PrintSquare()
    {
        cout << "Square = " << (i * i) << endl;
    }
 
public:
    void SetI(int x)
    {
        this->i = x;
    }
};
 
int main()
{
    CCalc obj;
 
    obj.PrintSquare();
 
    return 0;
 
}

There should be some mechanism that forces the user to provide an initial value to the data member i. If the object hasn't been initialized, then it should be impossible to call any public functions on that object. How to ensure that? There are two possible solutions:

  1. One is to ask the developer to insert a code at the start of every function to check whether initialization has been done, and if not done, some informative message should be printed. This looks a good possibility, but it adds too much work for a developer, and some careless ones might forget to do all this. And, even if some developer does decide to follow this path, showing messages each time might not be convenient. This is not a very practical possibility for basic initialization. But this technique is used in C++ where initialization alone is not the only thing required. For, example, you have a class that is initialized corectly, but the various member functions depend on success or failure of one or more other functions of the same class. In that case a bool variable[more correctly, a flag] is used, and it's value is checked before each function.
  2. The second, and more practical approach is to prevent the creation of an object, unless it has been initialized correctly. This check can be made the responsibility of the compiler, so that there is a built-in reminder for the person who is typing the code.

C++ takes the second of the above two possibilities. For this it adds a new special function called the constructor. The compiler has to make sure that the code for this function gets called at the time of the creation of the object. If the developer hasn't provided all the necessary inputs for the constructor, then it(the compiler) raises an error, similar to the one it raises when you call a function with fewer, or more arguments. Once, the object has been created, and its initialization occurs with a guarantee, the C++ object begins to behave much like the car and phone I talked at the beginning of this tutorial. A C++ object refuses to serve the public functions unless it has been initialized correctly.

The Constructor Function

These are the three basic characteristics of a constructor function.

  1. It's name is same as that of the class or struct.
  2. It doesn't return anything, not even void.
  3. It is automatically called by the compiler at the time of the creation of the object. The arguments have to be passed through the object identifier in the manner shown below. Assume that the class CCalc has a constructor function that takes an int. The complete code is shown somewhere later on this page.
    int main()
    {
        CCalc obj(7);
     
        obj.PrintSquare();
     
        return 0;
     
    }

In the code below we have created a class CCalc that contains a constructor. Even though a constructor can be public, private or protected, an object can be created in main only if the ctor[abbreviation for constructor] is public. Notice that there is no return type associated with the ctor. Otherwise it looks identical to a normal function.

class CCalc
{
private:
    int i;
 
public:
    void PrintSquare()
    {
        cout << "Square = " << (i * i) << endl;
    }
 
public:
    // constructor
    CCalc(int x)
    {
        this->i = x;
    }
};
 
int main()
{
    CCalc obj(7);
 
    obj.PrintSquare();
 
    return 0;
 
}

The above code delivers the correct output. The ctor ensures that the developer provide an initial value to the data member i.

Member List Initialization

A ctor can be used to provide initial values to the internal data in two ways: one is through the function body, and the other is through member list initialization. The following code shows the member list initialization.

class CCalc
{
private:
    int i;
 
public:
    void PrintSquare()
    {
        cout << "Square = " << (i * i) << endl;
    }
public:
 
    // member initializer list
    CCalc(int x) : i (x)
    {
 
    }
};
 
int main()
{
    CCalc obj(7);
 
    obj.PrintSquare();
 
    return 0;
}

If you have more than one data members, then they are comma separated as in the snippet below.

public:
 
    // member initializer list
    CCalc(int x, int y) : i (x), j(y)
    {
 
    }
};

You should develop a habit of using member initializer lists, sometimes they tend to be efficient. Consider a class that hosts an object of another class as shown in the following code. The class CB hosts an object of class CA. We want that the i of hosted object should get an initial value of 9, for which we set the i of the object in the parametrized constructor body. If you run this code you will observe an un-necessary call to the default constructor. This consumes machine cycles, and needs to be avoided.

class CA
{
public:
    int i;
 
public:
    CA(int x) : i(x)
    {
        cout << "Parametrized ctor called";
    }
 
public:
    CA()
    {
        cout << "Default ctor called";
    }
};
 
class CB
{
    CA ma;
 
public:
    CB(int x)
    {
        ma.i = x;
    }
};
 
int main()
{
    CB obj(9);
 
    return 0;
}

A better way of getting the same thing would be to call the parametrized ctor of CA through the member initializer list directly. This will help us avoid an un-necessary call to the default ctor. Here's how it can be done.

class CA
{
public:
    int i;
 
public:
    CA(int x) : i(x)
    {
        cout << "Parametrized ctor called";
    }
 
public:
    CA()
    {
        cout << "Default ctor called";
    }
};
 
class CB
{
    CA ma;
 
public:
    CB(int x) : ma(x)
    {
    }
};
 
int main()
{
    CB obj(9);
 
    return 0;
}

If you run the above code, you will be surprised to see that there is no call to the default constructor, and hence it is more efficient. You can also take note of the fact that if a class has no default constructor, then the only way of initialization of the hosted object is through the member initialization list. So, the member initialization list is a feature of the C++ language.

const Members in a Class

A class can contain constant data members. They can be given an initial value only once and cannot be changed at a later time. Constants help the compiler to generate a more efficient code. But if you cannot change a const, then where do you initialize it? You might think of giving it an initial value just at the time of declaration as shown below, but this is not allowed by a C++ compiler.

class CCircle
{
    // ERROR
    const float PI = 3.14f;
 
public:
    CCircle()
    {
    }
 

};

Although the above appears very intuitive, but it has a problem: how do you give it a value that the user might want to supply at runtime? It won't be possible if the developer has already hardcoded it. Once the developer has fixed a const value, then there is no scope for the user to supply his own value.

The second option that you might think of is to obtain and set the value in the ctor body, because a ctor code is, after all, being executed at the time of construction of the object, it makes some sense. I am talking of something like this.

class CCircle
{
    // ERROR
    const float PI;
 
public:
    CCircle()
    {
        // ERROR, const 
        // cannot be changed
        PI = 3.14f;
    }
};

This is not allowed by the compiler. It's because if you allow the user to alter the const in the ctor, then how would it be possible to stop the user from altering the value too many times in a long constructor code, because so long as the user is altering the const inside the ctor body, he is well within his rights to make as many alterations as he likes? But, in any case, we can surely see that it all boils down to two things -

  1. The const must be initialized through the ctor.
  2. But there should be atmost 1 chance of doing this.

How to do this? Well, if you haven't guessed it, then the right place is: Member Initializer List ! Have a look at the code below -

class CCircle
{
    const float PI;
 
public:
    CCircle() : PI(3.14f)
    {
    }
};

If you run the following code, you will get the compiler error: "PI is already initialized".

class CCircle
{
    const float PI;
 
public:
    // ERROR: PI is already initialized
    CCircle() : PI(3.14f), PI(3.14f)
    {
    }
};

When a software is written, the first target of a developer is to make things work, without worrying for efficiency/optimization. But once a software is working correctly, then the whole code is re-examined for efficiency. At this stage a developer looks for members and variables that can be marked const or static because they are, say, never being altered after the first initialization. Consider the following class that contains a member PI, which is not const, and the developer initializes it in the ctor body, probably because he is not in a habit of using member initializer lists.

class CCircle
{
    float PI;
 
public:
    CCircle()
    {
        PI = 3.14f;
    }
};
 
int main()
{
    return 0;
}

Later he finds that PI can be marked const. Now if he writes the const qualifier with the PI data member, then he will get an error because PI cannot be changed in the ctor body. Had he used the member initializer list earlier, he would have been able to save this headache. So the use of member initializer lists is recommended from code maintenance point of view also.

Compiler Written Constructors

You must be wondering how were you able to create objects earler? When you didn't know about constructors? And, when you didn't write any? A constructor is so important that if you do not provide a constructor, then the compiler creates one for you. Of course, don't expect it to be very smart - it just provides a constructor with empty body[nothing written for code], which is not able to do any initialization, it's just a namesake. In the following code the compiler adds the code secretly - it was always doing it earlier.

class CCalc
{
private:
    int i;
 
public:
    void PrintSquare()
    {
        cout << "Square = " << (i * i) << endl;
    }
};
 
int main()
{
    // compiler written ctor gets called
    CCalc obj;
 
    obj.PrintSquare();
 
    return 0;
 
}

If a ctor is not adding any code, then why is it there? Probably, for the backward compatibility with C. If you remember one of the previous chapters, I already told that struct is a link between C and C++.

A compiler creates a default constructor only if no constructors have been declared in the class. You can also ask the compiler not to generate a default constructor, by deleting it like this.

class MyClass 
{ 
 public: 
 
 MyClass() = delete; 
};

By deleting the default ctor you can prevent the creation of any objects through default ctor. Why would anyone do that? If your design needs it, then this option is available to you. Other options are to declare a default/or any parametrized ctor but not provide any definition. In that case even if the ctor is public, the linker will throw an error. You could also mark the default ctor with a body as private. This would lead to a compiler error if the user tries to create an object[from non-friends outside, like from main] through the default ctor. Objects of a class can still be created if the default ctor is private. Like this -

class CMyClass 
{ 
public:
    
    int i;
 
private:
 
    CMyClass() : i(0)
    {
    }
 
public:
    static CMyClass CreateObject()
    {
        // private ctor can be 
        // called from within a class
        CMyClass obj;
 
        return obj ;
    }
 
};
 
int main()
{
    // copy ctor comes into play here
    // to prevent this you will need to make
    // copy c-tor also private
    CMyClass obj = CMyClass::CreateObject();
 
    cout << obj.i << endl;
 
    return 0;
}

But if you delete a default ctor, then there is no possibilty of creating an object through the default ctor.

Syntax Clash

If you have noticed above, then you must be wondering why can't a default ctor be called with the empty round brackets? A code like the following gives an error or warning.

class CMyClass
{
    int i;
 
public:
 
    CMyClass() : i(0)
    {
 
    }
 
public:
 
    CMyClass(int x) : i(x)
    {
 
    }
};
 
int main()
{
    // ERROR/WARNING Why?
    CMyClass obj();
 
    return 0;
}

It is because the statement: CMyClass obj(); can have two meanings. It could also be a declaration for a function called obj that returns CMyClass. It is because of this clash of syntax that the above statement either generates a warning or an error, depending on your compiler. But when calling a paramterized ctor, there is no such clash, so the call is done as in a function call syntax.

Implicit Construction

If a class has a costructor that takes a single argument, or if it has a constructor that takes multiple arguments but all except the first one are defaulted, so that effectively the constructor takes a single argument, then the compliler can create an object from an instance of that type of argument. Consider the class below.

class CMyClass 
{ 
public:
    
    int i;
 
public:
 
    CMyClass(int x) : i(x)
    {
    }
};

This class contains a ctor that takes a single argument of type int. The compiler can create an object out of an int because it knows that there is a constructor that takes an int argument. So the following code will create an object of the class by calling the constructor that takes an int arg.

int main()
{
    // implicitly calls the ctor that takes an int
    CMyClass obj = 10;
 
    cout << obj.i << endl;
 
    return 0;
}

The above behaviour can be suppressed, because it can lead to un-expected and in-advertent bugs in your code that could be difficult to find out in the absence of compiler warnings or errors. To suppress this behaviour you can use the explicit keyword in front of the constructor, like as shown in the code below.

class CMyClass 
{ 
public:
    
    int i;
 
public:
 
    explicit CMyClass(int x) : i(x)
    {
    }
};
 
int main()
{
    // ERROR
    CMyClass obj = 10;
 
    cout << obj.i << endl;
 
    return 0;
}

Constructing an Array of Objects

If your class contains a default ctor, then a stack array can be created in the same manner as you would for, say, an int - using the square bracket syntax.

class CMyClass 
{ 
    int i;
 
public:
    CMyClass() : i(0)
    {
    }
public:
    void print()
    {
        cout << "i = " << i << endl;
    }
};
 
int main()
{
    CMyClass arr[10];
 
    int numObjects = sizeof(arr)/sizeof(arr[0]);
 
    for(int x = 0; x < numObjects; x++)
    {
        arr[x].print();
    }
 
    return 0;
}

From the above code we can think of an interesting observation - sizeof(CMyClass) is the number of bytes for an object of the class. What would be the size of an empty class? Zero, because it contains no data members? Assume, for the time being, that the size is indeed zero. Then all items of an array of objects of the class would have the same address: &arr[0] will be same as &arr[3], etc., But this would lead to an ambiguity. So the C++ standard states that the size of an empty class or struct should be atleast 1 byte, and leaves it to the compiler to decide the figure for itself, for its optimizations. Usually, all standard compilers keep the size of an empty class as 1 byte. Empty structs are not allowed in C, whereas in C++, a struct and class could be empty. You can run this program to verify the facts yourself.

class CMyClass 
{ 
};
 
int main()
{
    cout << sizeof(CMyClass) << endl;
    return 0;
}

An array of class objects can be easily created on the heap as well, provided the class has a default constructor. Heap objects can be created using the new operator, and the delete operator must be used to release the allocation.

class CMyClass 
{
    int i;
 
public:
    CMyClass() : i(0)
    {
 
    }
 
public:
 
    void print()
    {
        cout << i << endl;
    }
};
 
int main()
{
    CMyClass * arr = new CMyClass[10];
 
    for (int i = 0; i < 10; i++)
    {
 
        arr[0].print();
    }
 
    // release memory
    delete[] arr;
 
    return 0;
}

If a class doesn't have a default ctor, then an array cannot be created on the stack by using the square bracket syntax alone - CMyClass arr[3]; - this statement will cause a compiler error because the paramterized ctors would want their arguments, and that can't be done here. The workaround is to use temporaries. See the code below.

class CMyClass 
{
public:
    int     i;
    char k;
 
public:
    CMyClass(int x, char y) : i(x), k(y)
    {
    }
};
 
int main()
{
    CMyClass arr[4] = 
    {
        CMyClass(2, 'a'),
        CMyClass(-55, 'c'),
        CMyClass(99, 'h'),
        CMyClass(29, 'u'),
    };
 
    return 0;
}

An array of a class with a non-default ctor cannot be easily created on the heap, as you can see in the following code. How would you pass the arguments? Yes, there is no direct way. But workarounds exist.

class CMyClass 
{
public:
    int i;
 
public:
    CMyClass(int x) : i(x)
    {
    }
};
 
int main()
{
    // ERROR
    CMyClass * cmc = new CMyClass[2];
 
    return 0;
}

One simplest thing is to put a default ctor, and then add functions to set initial values for your data members. But if your code structure requires that no default ctors be present, then you can create an array of pointers on the heap, and then use a loop to initialize each item by calling it's default ctor.

class CMyClass 
{
public:
    int i;
 
public:
    CMyClass(int x) : i(x)
    {
    }
 
public:
    void print()
    {
        cout << i << endl;
    }
};
 
int main()
{
    const int NUMOBJECTS = 4;
 
    CMyClass ** cmc = new CMyClass*[NUMOBJECTS];
 
    for(int x = 0; x < NUMOBJECTS; x++)
    {
        cmc[x] = new CMyClass(7);
    }
 
    // call functions
    for(int x = 0; x < NUMOBJECTS; x++)
    {
        cmc[x]->print();
    }
 
    // release memory
    for(int x = 0; x < NUMOBJECTS; x++)
    {
        delete cmc[x];
    }
 
    delete[] cmc;
 
    return 0;
}

Another alternative is to use STL C++ classes like vector to manipulate heap allocated collections of objects.

Classroom Training

Classroom training in C/C++ is available at our training institute. Click here for details. You can also register yourself here.

Video Tutorial

We have created a video tutorial that can be downloaded and watched offline on your windows based computer. It is in the form of an exe file. No installation is required, it runs by double clicking the file. Since the exe file is hosted on the Google Drive, it should be very safe because Google itself checks for any virus or malware. The video can be watched offline, no internet is required.

Pricing

This single video will cost you USD $5. When you download the video, you will be able to watch the first few minutes for free, as a sample. The video app will prompt you for payment through PayPal and other payment options. If you want ALL VIDEOS, NOT JUST THIS ONE then go here: Complete Set of C/C++ Video Tutorials The entire set is priced at USD $50.

Screenshots

This is a screenshot of the software that should give you a good idea of the available functionality. Click on the image to see a larger view. screenshot of the video being played in the software

Installation

This software doesn't require any installation. Just download and double-click to run it. It doesn't require administrative priviliges to run. It runs in limited access mode, so should be very safe.

supports windows xp and later Supported Operating Systems

These videos can be run on 32-bit as well as 64-bit versions of the Microsoft Windows Operating Systems. Windows XP and all later OS are supported. If you want to run it on Windows XP and Windows Vista, then you must also have the .NET Framework Version 3.5 installed on your machines. Those users who have Windows 7 and later donot have to worry because these operating systems already have the .NET Framework installed on them.

Download Links

IMPORTANT NOTE: This download contains ONLY ONE video. The video is about the topic of this tutorial.

Want ALL Videos? If you want ALL VIDEOS, NOT JUST THIS ONE then go here: Complete Set of C/C++ Video Tutorials. TIP: If you plan to buy these videos, then it would be more economical to buy the entire set.

DISCLAIMER: Even though every care has been taken in making this software bug-free, but still please take a proper backup of your PC data before you use it. We shall not be responsible for any damages or consequential damages arising out of the use of this software. Please use it solely at your own risk.

Please download the software here.
download the video Constructors



Creative Commons License
This Blog Post/Article "Constructors" by Parveen (Hoven) is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
Updated on 2020-02-07. Published on: 2015-10-05