C++ Derived Classes and Object Destruction

While working on lebookread I realized that the the destructor for my reader classes would never be called. lebook read has a base class (FormatReader) that exports all of the necessary functionality for use by applications using the library. All of the readers are a subclass of FormatReader. The library will find the appropriate reader for the specified ebook create a reader object and return it as a FormatReader pointer.

When you are dealing with a pointer p of type base that points to an object of type derived you need to take special care. To have the destruction of p call the derived and base destructor the base class must have a virtual destructor. Otherwise only the base class’s destructor will be called. This is one of those little things to look out for when dealing with C++.

Here is some example code to demonstrate the above.

main.cpp

#include <iostream>

#include "base.h"
#include "deriv.h"

using namespace std;

int main(int argc, char** argv)
{
    cout << &quot;Base *b = new Base();&quot; << endl;
    cout << &quot;delete b;&quot; << endl;
    Base *b = new Base();
    cout << &quot; --- &quot; << endl;
    delete b;
    cout << &quot; --- &quot; << endl;
    cout << &quot;b destroyed&quot; << endl;
    
    cout << endl;
    
    cout << &quot;Deriv *d = new Deriv();&quot; << endl;
    cout << &quot;delete d&quot; << endl;
    Deriv *d = new Deriv();
    cout << &quot; --- &quot; << endl;
    delete d;
    cout << &quot; --- &quot; << endl;
    cout << &quot;d destroyed&quot; << endl;
    
    cout << endl;
    
    cout << &quot;Base *c = new Deriv();&quot; << endl;
    cout << &quot;delete c&quot; << endl;
    Base *c = new Deriv();
    cout << &quot; --- &quot; << endl;
    delete c;
    cout << &quot; --- &quot; << endl;
    cout << &quot;c destroyed&quot; << endl;

    return 0;
}

base.h

#ifndef BASE_H
#define BASE_H

class Base
{
public:
    ~Base();
};

#endif /* BASE_H */

base.cpp

#include <iostream>

#include "base.h"

using namespace std;

Base::~Base()
{
    cout << &quot;base dest&quot; << endl;
}

deriv.h

#ifndef DERIV_H
#define DERIV_H

#include "base.h"

class Deriv : public Base
{
public:
    ~Deriv();
};

#endif /* DERIV_H */

deriv.cpp

#include <iostream>

#include "deriv.h"

using namespace std;

Deriv::~Deriv()
{
    cout << &quot;deriv dest&quot; << endl;
}

The output of this will be:

$ ./a.out 
Base *b = new Base();
delete b;
 --- 
base dest
 --- 
b destroyed

Deriv *d = new Deriv();
delete d
 --- 
deriv dest
base dest
 --- 
d destroyed

Base *c = new Deriv();
delete c
 --- 
base dest
 --- 
c destroyed

Notice that when destroying c only the Base’s destructor is called. To fix this and have both Base and Deriv’s destructors called just make Base’s destructor virtual.

#ifndef BASE_H
#define BASE_H

class Base
{
public:
    virtual ~Base();
};

#endif /* BASE_H */

This simple change will cause the output to become:

$ ./a.out 
Base *b = new Base();
delete b;
 --- 
base dest
 --- 
b destroyed

Deriv *d = new Deriv();
delete d
 --- 
deriv dest
base dest
 --- 
d destroyed

Base *c = new Deriv();
delete c
 --- 
deriv dest
base dest
 --- 
c destroyed

Now when destroying c the destructor for both Base and Deriv are called.

To compile

$ g++ base.cpp deriv.cpp main.cpp

One thought on “C++ Derived Classes and Object Destruction

  1. Right. This is because the keyword virtual causes function lookup to occur at runtime – by selecting the function from the virtual function table. If you omit the keyword, then function lookup is done at compile time, and the address of the function corresponding to the type of variable is chosen, which means in your middle case above, the base function is chosen, since the variable is a base variable. Once you make it virtual, it doesn’t bind at compile time, it consults the lookup table at runtime.

Comments are closed.