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++
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #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
1 2 3 4 5 6 7 8 9 10 11 12 13 | #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:
1 2 3 4 5 6 7 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #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
1 2 3 4 5 6 7 8 9 10 11 | #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:
1 2 3 4 5 6 7 | 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
1 2 3 4 5 6 7 8 9 10 11 | struct TBrick { public: TBrick(); double CementVolume(); void ShowProperties(); private: double Length; double Height; double Thickness; }; |
And implemented as
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #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:
1 2 3 4 5 6 7 8 9 10 11 12 | #include <iostream> using namespace std; #include "Bricks.h" int main() { TBrick Mango; Mango.ShowProperties(); return 0; } |
This would produce the following result:
1 2 3 4 5 6 7 | 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:
1 2 3 4 5 6 | TBrick::TBrick() { Length = 4.15; Height = 3.55; Thickness = 3.75; } |
This time, the same program would produce a sound result:
1 2 3 4 5 6 7 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | #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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #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:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #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:
1 2 3 4 5 6 | TBrick::TBrick(double L, double h, double t) { Length = L; Height = h; Thickness = t; } |
Main File: Main.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 | #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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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... |