Question

I am trying to understand virtual destructors. The following is a copy paste from this page When to use virtual destructors?

Here, you'll notice that I didn't declare Base's destructor to be virtual. Now, let's have a look at the following snippet:

Base *b = new Derived(); // use b 
delete b; // Here's the problem!

[...] If you want to prevent the deletion of an instance through a base class pointer, you can make the base class destructor protected and non-virtual; by doing so, the compiler won't let you call delete on a base class pointer.

I don't understand why the deletion is prevented by having a protected non-virtual base class destructor. Doesn't the compiler think that we're trying to call delete from a base class object? What does protected have to do with that?

Was it helpful?

Solution

The C++ Standard has this to say about delete (section 5.3.5p10):

Access and ambiguity control are done for both the deallocation function and the destructor (12.4, 12.5).

Therefore, only code that has access to the destructor is able to use delete. Since the destructor is protected, that means that no one can call delete on a pointer of type Base*. Only subclasses can use the destructor at all (and the only thing that will is the subclass's own destructor, as part of the subobject destruction process).

Of course, the subclass should make its own destructor public, allowing you to delete objects through the subclass type (assuming that is the correct actual type).

NOTE: Actually, other members of Base can do delete (Base*)p; since they have access. But C++ assumes that someone using this construct will not be doing that -- C++ access control only provides guidance to code outside your class.

OTHER TIPS

delete b; effectively performs b->~Base(); deallocate(b);. The first part - calling the destructor - would fail to compile if the destructor is inaccessible (in the same way that calling any other inaccessible method fails).

From my understanding (based on this page), the only case we would like to use the non-virtual and protected destructor in the base class is the following:

#include <iostream>

struct unary_function {
protected:
  ~unary_function() {
      std::cout << "unary_function" << std::endl;
  }
};

struct IsOdd : public unary_function {
public:
    bool operator()(int number) { 
        return (number % 2 != 0); 
    }
};

void f(unary_function *f) {
  // compile error
  // delete f;
}

int main() {
  // unary_function *a = new IsOdd;
  // delete a;

  IsOdd *a = new IsOdd;
  delete a;

  getchar();
  return 0;
}

therefore, you can only do this:

  IsOdd *a = new IsOdd;
  delete a;

or

  IsOdd c;

never these:

  unary_function *a = new IsOdd;
  delete a;

therefore, with nonvirtual protected destructor, the compiler would give an error when you try to use this

void f(unary_function *f) {
  delete f; 
  // this function couldn't get compiled because of this delete. 
  // you would have to use the derived class as the parameter 
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top