3.10 Destructors



If you think C++ is not overly complicated, just what is a protected abstract virtual base pure virtual private destructor and when was the last time you needed one?

 
 --Tom Cargill

Since the responsibility for the initialisation of the class is in the hands of the programmer of the class, the responsibility for the destruction of the class should also be the responsibility of the programmer. In C++ we can write a destructor for a class that performs some clean-up operations and even notifications. To define a destructor for a class the ~ symbol is used in front of the class name, so for the Account class you would use:

 class Account{
      // state definition	
	public:
      Account(int theNumber, float theBalance);
      virtual ~Account(); //destructor

      // other member methods here.
 };
 
 Account::~Account()
 {
   cout << "Account object being destroyed!" << endl;
 }

Note: A similar destructor is also written for the CurrentAccount class.

The destructor must take no parameters and cannot return a result. A constructor cannot be virtual, but a destructor can (and should) be virtual (we will discuss this later).

When is a destructor called?

  • It is not invoked explicitly.

  • It is called when an object goes out of scope.

Suppose an object of the Account class was created as below.

 
 // main() method where CurrentAccount is a child of the Account class,
 // with a destructor as defined just above.
 
 int main()
 {
    CurrentAccount b = CurrentAccount(50.0, 12345, 200.0);
    b.display();
 }

The full source code for this example is listed in AccountDestructor.cpp What would happen? Since CurrentAccount is a child of the Account class then destruction of an object of the CurrentAccount object will result in the Account destructor being called. When this example is run you will get the output as in Figure 3.8, “The output from the Account Destructor Example.”.

Figure 3.8. The output from the Account Destructor Example.

The output from the Account Destructor Example.

In the Figure 3.8, “The output from the Account Destructor Example.” screen grab it can be seen that the CurrentAccount destructor followed by the Account destructor were called, just after the main() method ended, and just before the application ran to completion.

If you don't declare a destructor, C++ generates a default destructor, that frees up the memory of the object.

This is suitable for most classes, however a destructor may be required for specific actions:

  • Notifying other objects about an imminent destruction.

  • Closing open files, database connections, sockets etc.

  • Freeing dynamically allocated data. If an object does not free data that is dynamically allocated, then that memory will remain locked until the application terminates.

The problems with loosing dynamically allocated memory can be prevented from occurring by using the following structure:

  class SomeClass{
		// the states
	public:
		SomeClass();
		virtual ~SomeClass(); //The destructor
		// other methods
  };

  SomeClass::SomeClass(){
	// Allocate extra space here in
	// the constructor!
  }

  SomeClass::~SomeClass(){
	// De-allocate that extra space!
  }

In this case the programmer need only worry about freeing the extra space allocated in the constructor, not about the space for the object (or states) itself!

The destructor for the base class must be called when an object of a derived class is destroyed. This happens automatically! (in the order):

  • C++ calls the programmer defined destructor for the derived class.

  • C++ then calls the programmer defined destructor for the base class.

  • C++ then frees the object space itself.

This is the opposite way to how an object is constructed!




These notes are copyright Dr. Derek Molloy, School of Electronic Engineering, Dublin City University, Ireland 2013-present. Please contact him directly before reproducing any of the content in any way.
ċ
AccountDestructor.cpp
(2k)
Derek Molloy,
19 Oct 2013, 05:05
Comments