Tuesday, March 27, 2012

Virtual destructors in C++

C++ gives default destructor, if you not define the destructor. But this wont be help full if you use dynamic memory allocation. You need to write the destructor function manually to deallocate the memory. This works fine if there is no derived class. If there is any derived class with memory allocation, you should use virtual destructors. see the sample code below.

#include<iostream>
using namespace std;

class base
{
    public:
    base()    //constructor
    {
        cout<<"this is base CTOR\n";
    }

    ~base()    //not a virtual destructor
    {
        cout<<"this is base DTOR\n";
    }
};
class derived:public base
{
    char *str;
    public:
    derived()
    {
        cout<<"this is derived CTOR\n";
        str = new char[20]; // allocating space
    }
    ~derived()
    {
        cout<<"this is derived DTOR\n";
        delete[] str; // deleting
    }
};
main()
{
    derived *d = new derived(); // creating derived object
    base *b = d; // assigning derived object to base object
    delete b; // deleting base object

}

Output:
this is base CTOR
this is derived CTOR
this is base DTOR

In the above sample code, there is derived class with char pointer member data. Memory is allocated in derived constructor and deallocated in derived destructor. In main() function , derived object is created using new,  this is assigned to base object. And base object is deallocated using delete.  In the output you got, base constructor, derived constructor, and base destructor. And there is no derived destructor. Actually, we allocated memory in derived constructor.  so there is a memory leak, because we are not freed the allocated memory.

To avoid such problems, we need to use virtual destructors. Actually compiler looks for the base destructor and checks for the virtual keyword for the destructor, if it finds virtual keyword, it further goes to derived destructor and goes on till the refered derived class. from there it calls destructor one by one from derived destructor to till it reaches base destructor.  If there is no virtual keyword in the base destructor, it stops in base destructor itself. See the sample code with virtual destructor.


Code with virtual destructor:

#include<iostream>
using namespace std;

class base
{
    public:
    base()    // base constructor
    {
        cout<<"this is base CTOR\n";
    }
    virtual ~base()    // virtual destructor
    {
        cout<<"this is base DTOR\n";
    }
};
class derived:public base
{
    char *str;
    public:
    derived()
    {
        cout<<"this is derived CTOR\n";
        str = new char[20]; // allocating space
    }
    ~derived()
    {
        cout<<"this is derived DTOR\n";
        delete[] str; // deleting
    }
};
main()
{
    derived *d = new derived(); // creating derived object
    base *b = d; // assigning derived object to base object
    delete b; // deleting base object

}

Output:
this is base CTOR
this is derived CTOR
this is derived DTOR
this is base DTOR


In this example, we used virtual destructor, when it calls deleting base pointer, it looks for the base destructor, then it looks for the virtual  keyword for the destructor, it will get the keyword, so it looks for the derived destructor, it finds the destructor, and there is no derived classes, so it calls the derived destructor, then it calls the base destructor as shown above. In red color output , is the derived destructor.

No comments:

Popular Posts