Published: August 6, 2008
By Richard G. Baldwin
File: AdvCpp00135
The purpose of this series of tutorial lessons is to help you progress from procedural programming using C++ to object-oriented programming (OOP) using C++. As I have mentioned in earlier lessons (see Resources), most of the code in these lessons is being written in such a way as to make it compatible with the display of output data on the command-line screen using Dev-C++. However, you can easily modify the code to make it compatible with other C++ programming tools.
This lesson presents and explains two different programs that illustrate the behavior of constructors and destructors.
I recommend that you open another copy of this document in a separate browser window and use the following links to easily find and view the figures and listings while you are reading about them.
I recommend that you also study the other lessons in my extensive collection of online programming tutorials. You will find a consolidated index at www.DickBaldwin.com.
When you create a class in C++, you are, in effect, creating a new data type. Having created the new type, you can declare instances of the type in the form of variables commonly called objects. In addition to data stored in the object, the class can also define member functions which provide the means for manipulating the data stored in the object. These member functions provide the interface between the encapsulated data in the object and the other parts of the program.
Constructors and destructors
Specially formatted member functions can also be provided that execute automatically when an object is created and destroyed. The special functions that execute automatically when the object is created are commonly called constructors. Constructors were invented for the express purpose of initializing the object's data to specified values when the object is created.
The special functions in the latter category are commonly called destructors. The purpose of destructors is to eliminate the data when it is no longer needed.
A common use for destructors is to free dynamically-allocated memory at such time as the data that occupies that memory is no longer needed. (Dynamically allocated memory will be the topic of future lessons.) The failure to properly free dynamically-allocated memory when appropriate leads to a fairly common form of program failure, which is often referred to as a memory leak.
Overloading
With the exception of destructors, the member functions in a class can be
overloaded to perform different actions whenever the type or number (or
both) of the arguments differs from one call to the next. Constructors are
no exception to this rule. It is common practice to use overloaded constructors
that initialize the data in different ways, depending on how an object is
specified when it is declared. These are sometimes referred to as
parameterized constructors.
A class definition in C++ creates a new data type from which you can create instances (objects). The object can contain data, member functions, multiple overloaded constructors, and a single destructor.
Constructors should be used to initialize the values of the data items contained in the object. The destructor should be used to dispose of those data items in an orderly way when the data is no longer needed, making certain to avoid memory leaks.
This lesson presents and explains two different programs that illustrate the behavior of constructors and destructors.
A C++ class may have multiple overloaded constructors and a single destructor.
It is very common for parts of your program to require initialization. When working with real problems, virtually every object that you create will probably require some sort of initialization. C++ does not generally provide default initialization values. The failure to properly initialize variables and objects in C++ leads to a fairly common form of runtime program failure resulting from the processing of left-over garbage in memory as though it is valid data.
To address this situation, C++ allows a constructor
to be included in a class declaration. The constructor for a class is
called each time an object of that class is created. Thus, any initialization
that needs to be performed on an object can be performed by the code in the
constructor when the constructor is automatically executed.
A constructor has the same name as the class of which it is a part and
has no return type. The example program in Listing 6 illustrates the behavior
of a constructor.
Will explain in fragments
I will explain this program in fragments. The fragment in Listing 1 shows
the beginning of the program and the class declaration.
Listing 1. Class declaration for the program named Prog135A.
#include <iostream> using namespace std; class MyClass{ int var; //private variable public: MyClass(); //constructor void show();//display the value of the variable "var" }; //end of class declaration |
The constructor declaration is highlighted in blue boldface. Note that the name of the constructor is the same as the name of the class and that it does not specify a return type.
In this case, the constructor doesn't require any incoming parameters. However, there could be multiple overloaded constructors each one requiring different numbers and/or types of parameters.
Definition of the constructor and the show function
Listing 2 shows the definition of the constructor and the function named show. The constructor is highlighted in blue boldface. Note that the constructor must be public for the program to compile because it is called from outside the class.
Listing 2. Definition of the constructor and the show function.
MyClass::MyClass(){ //define the constructor cout << " In the constructor setting var to 10\n"; var = 10; //set var to a value of 10 }//end constructor definition void MyClass::show(){ //define the show function cout << " In the show function, var = " << var << "\n"; }//end show function |
In this example, the value of the private data member var is initialized to a value of 10 by code in the constructor named MyClass. The constructor is called when the object named obj is created by the code in the main function (see Listing 3). An object is created when that object's declaration statement is executed.
The main function
The main function in the program named Prog135A is shown in Listing 3.
Listing 3. The main function in the program named Prog135A.
int main(){ cout << "Create the object and execute the constructor\n"; MyClass obj; cout << "Execute the show function\n"; obj.show(); //return 0; //Following statements cause Dev-C++ output to remain // on the screen system("PAUSE"); return EXIT_SUCCESS; }// end main |
Construct the object
The main function begins by declaring an object named obj of the class named MyClass. This is the point in time when the constructor code shown in Listing 2 is executed causing a value of 10 to be stored in the private member variable named var that belongs to the new object. The main function also causes some text to appear on the command-line screen.
Display the contents of the object
Then the main function calls the public show method, which is defined in Listing 2, and which belongs to the object. The code in the show method displays the current value stored in the variable named var belonging to the object on which the function is called. The value of var is displayed on the command-line screen, producing the screen output shown in Figure 1 when the program is compiled and executed using Dev-C++.
Figure 1. Screen output from the program named Prog135A
Create the object and execute the constructor In the constructor setting var to 10 Execute the show function In the show function, var = 10 Press any key to continue . . . |
As the name implies, a destructor has a behavior that is the opposite of a constructor. While a constructor builds an object up, a destructor tears it down.
The destructor is called when the object to which it belongs is destroyed. This can happen in a variety of ways, but it usually means that either the object has gone out of scope, or the program code has purposely destroyed the object.
Cleanup code is frequently needed
When working with objects, it is very common to have to perform some actions when an object is destroyed. For example, an object that allocates memory when it is created will need to free that memory when it is destroyed. Otherwise, the program will exhibit a characteristic commonly referred to as a memory leak.
The destructor's name
Like a constructor, the name of a destructor must match the name of the class to which it belongs, with the following exception. You include a destructor in a class declaration by preceding the name with a tilde (~). A destructor never receives any parameters and can't be overloaded.
Destruction of an object
Local objects are destroyed when they go out of scope. Global objects are destroyed when the program ends. Dynamically allocated objects are destroyed when the program purposely destroys them, or when the program ends.
A sample program with a destructor
The sample program that is presented in Listing 7 adds a destructor to the previous program and demonstrates that the destructor is called when the program ends.
Class declaration for the program named Prob135B
As before, I will discuss and explain this program in fragments. The class declaration for the program is shown in its entirety in Listing 4.
Listing 4. Class declaration for the program named Prob135B.
#include <iostream> using namespace std; class MyClass{ int var; //private variable public: MyClass(); //constructor ~MyClass(); //destructor void show();//display the value of the variable "var" }; //end of class declaration |
The only thing that is new in Listing 4, as compared to Listing 1 is the declaration of the destructor, which is highlighted in blue boldface in Listing 4. Note the tilde in the syntax for the destructor. Also note that the destructor doesn't receive any parameters.
Definition of constructor, destructor and show function
Listing 5 shows the definition of the constructor, the destructor and the show function.
Listing 5. Definition of constructor, destructor and show function.
MyClass::MyClass(){ //define the constructor cout << " In the constructor setting var to 10\n"; var = 10; //set var to a value of 10 }//end constructor definition MyClass::~MyClass(){//define the destructor,note the tilde cout << " In the destructor...\n"; } //end definition of destructor void MyClass::show(){ //define the show function cout << " In the show function, var = " << var << "\n"; }//end show function |
The only thing that is new in Listing 5 relative to Listing 2 is the definition of the destructor, which is highlighted in blue boldface in Listing 5.
The destructor doesn't have anything important to do in this simple program. It displays a message on the command-line screen to demonstrate that it is executed when the main function terminates causing the object to go out of scope and to be destroyed.
The main function
The main function in this program is identical to that shown in Listing 3, so I won't discuss it further.
The screen output
The screen output from running this program is shown in Figure 2.
Figure 2. Screen output from the program named Prog135B.
Create the object and execute the constructor In the constructor setting var to 10 Execute the show function In the show function, var = 10 Press any key to continue . . . In the destructor... |
A little trickiness here
Note that viewing the screen output produced by the destructor (shown in blue boldface in Figure 2) is a little tricky. If you include the special Dev-C++ code shown at the end of Listing 3 and execute the program from within Dev-C++, you won't see the output produced by the destructor. This is because the line of text that reads "Press any key to continue . . ." and the pause that follows the display of that text is produced by the special Dev-C++ code at the end of Listing 3.
In effect, this special code causes the execution of the program to pause so that you can view the output before the main function returns and the function terminates. However, the destructor isn't executed until the main function returns causing the object to go out of scope and to be destroyed. When you press a key as instructed, the output screen disappears immediately and you don't see the last line of output that is produced by the destructor.
Must run directly from the command line
You will need to compile this program and then execute it directly from a command line to see the output produced by the destructor. In this case, you can either leave the special Dev-C++ code in the main method (see Listing 3) and press a key when instructed to do so, or you can replace that code with a simple return statement. In the latter case you won't be prompted to press a key to continue. In either case, the output produced by the destructor should be the last thing that you see before control returns to the command-line prompt.
Technically, a constructor or a destructor can perform just about any type of operation that is supported by C++ code. The code that occurs within these special functions does not have to initialize or remove anything. However, having a constructor or destructor perform actions not directly related to the initialization or orderly destruction of an object makes for very poor programming style and should be avoided.
A class definition in C++ creates a new data type from which you can create instances (objects). The object can contain data, member functions, multiple overloaded constructors, and a single destructor.
Constructors should be used to initialize the values of the data items contained in the object. The destructor should be used to dispose of those data items in an orderly way, making certain to avoid memory leaks.
This lesson presented and explained two different programs that illustrate the behavior of constructors and destructors.
Listing 6. Source code for the program named Prog135A.
//File Prog135A /********************************************************* Constructors This program illustrates the behavior of a constructor. *********************************************************/ #include <iostream> using namespace std; class MyClass{ int var; //private variable public: MyClass(); //constructor void show();//display the value of the variable "var" }; //end of class declaration MyClass::MyClass(){ //define the constructor cout << " In the constructor setting var to 10\n"; var = 10; //set var to a value of 10 }//end constructor definition void MyClass::show(){ //define the show function cout << " In the show function, var = " << var << "\n"; }//end show function //Test the class int main(){ cout << "Create the object and execute the constructor\n"; MyClass obj; cout << "Execute the show function\n"; obj.show(); //return 0; //Following statements cause Dev-C++ output to remain // on the screen system("PAUSE"); return EXIT_SUCCESS; }// end main |
Listing 7. Source code for the program named Prog135B.
//File Prog135B /********************************************************* Constructors This program illustrates the behavior of a destructor. *********************************************************/ #include <iostream> using namespace std; class MyClass{ int var; //private variable public: MyClass(); //constructor ~MyClass(); //destructor void show();//display the value of the variable "var" }; //end of class declaration MyClass::MyClass(){ //define the constructor cout << " In the constructor setting var to 10\n"; var = 10; //set var to a value of 10 }//end constructor definition MyClass::~MyClass(){//define the destructor,note the tilde cout << " In the destructor...\n"; } //end definition of destructor void MyClass::show(){ //define the show function cout << " In the show function, var = " << var << "\n"; }//end show function //Test the class int main(){ cout << "Create the object and execute the constructor\n"; MyClass obj; cout << "Execute the show function\n"; obj.show(); //return 0;//cause the object to go out of scope //Following statements cause Dev-C++ output to remain // on the screen. system("PAUSE"); return EXIT_SUCCESS; }// end main |
Copyright 2008, Richard G. Baldwin. Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.
Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas. He is the author of Baldwin's Programming Tutorials, which have gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.
In addition to his programming expertise, Richard has many years of practical experience in Digital Signal Processing (DSP). His first job after he earned his Bachelor's degree was doing DSP in the Seismic Research Department of Texas Instruments. (TI is still a world leader in DSP.) In the following years, he applied his programming and DSP expertise to other interesting areas including sonar and underwater acoustics.
Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.
-end-