4

I've written this test code that uses three types: struct One is a normal type with no virtual members, struct Two : One has a pure virtual function and a virtual destructor, and struct Three : Two implements Two's interface.

#include <iostream>

struct One
{
    ~One() {
        std::cout << "~One()\n";
    }
};

struct Two : One
{
    virtual ~Two() {
        std::cout << "~Two()\n";
    }

    virtual void test() = 0;
};

struct Three : Two
{
    virtual ~Three() {
        std::cout << "~Three()\n";
    }

    virtual void test() {
        std::cout << "Three::test()\n";
    }
};

int main()
{
    Two* two = new Three;
    two->test();

    One* one = two;
    delete one;
}

Unsurprisingly, the output was this:

Three::test()
~One()

Is there any way to fix this other than making every destructor virtual? Or should programmers just be careful not to run into this situation? I find it odd that there's no warning when compiling this.

j0k
  • 22,600
  • 28
  • 79
  • 90
Paul Manta
  • 30,618
  • 31
  • 128
  • 208
  • An easy fix: Use private or protected inheritance from `One` and expose functionality through using declarations. – Xeo Jan 07 '12 at 11:39

4 Answers4

2

The only "fix" is not to delete the objects through a pointer to One.

If this is a frequent problem, or not, depends on how your classes are used. For example, the standard library contains structs like unary_function without a virtual destructor, but we hardly ever see it misused like this.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
2

delete one invokes undefined behaviour, because the dynamic type of the object does not match the static type, and the static type does not have a virtual destructor.

The usual way to avoid problems like this is to make destructors be either public and virtual, or protected and non-virtual (on classes that are expected to be used in this way).

Mankarse
  • 39,818
  • 11
  • 97
  • 141
1

You must be careful and make One's destructor virtual. Some compilers do warn about this.

Gary
  • 5,642
  • 1
  • 21
  • 41
1

If you want working destructors in derived classes then you must define them as virtual. It is the only way.

gumik
  • 603
  • 1
  • 5
  • 14