While working on lebookread I realized that 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 << "Base *b = new Base();" << endl;
    cout << "delete b;" << endl;
    Base *b = new Base();
    cout << " --- " << endl;
    delete b;
    cout << " --- " << endl;
    cout << "b destroyed" << endl;

    cout << endl;

    cout << "Deriv *d = new Deriv();" << endl;
    cout << "delete d" << endl;
    Deriv *d = new Deriv();
    cout << " --- " << endl;
    delete d;
    cout << " --- " << endl;
    cout << "d destroyed" << endl;

    cout << endl;

    cout << "Base *c = new Deriv();" << endl;
    cout << "delete c" << endl;
    Base *c = new Deriv();
    cout << " --- " << endl;
    delete c;
    cout << " --- " << endl;
    cout << "c destroyed" << 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 << "base dest" << 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 << "deriv dest" << 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