Virtuals in destructors
There’s something that happens
during destruction that you might not immediately expect. If you’re inside
an ordinary member function and you call a virtual function, that function is
called using the late-binding mechanism. This is not true with destructors,
virtual or not. Inside a destructor, only the “local” version of the
member function is called; the virtual mechanism is ignored.
//: C15:VirtualsInDestructors.cpp
// Virtual calls inside destructors
#include <iostream>
using namespace std;
class Base {
public:
virtual ~Base() {
cout << "Base1()\n";
f();
}
virtual void f() { cout << "Base::f()\n"; }
};
class Derived : public Base {
public:
~Derived() { cout << "~Derived()\n"; }
void f() { cout << "Derived::f()\n"; }
};
int main() {
Base* bp = new Derived; // Upcast
delete bp;
} ///:~
During the destructor call,
Derived::f( ) is not called, even though f( ) is
virtual.
Why is this? Suppose the virtual
mechanism were used inside the destructor. Then it would be possible for
the virtual call to resolve to a function that was “farther out”
(more derived) on the inheritance hierarchy than the current destructor. But
destructors are called from the “outside in” (from the most-derived
destructor down to the base destructor), so the actual function called would
rely on portions of an object that have already been destroyed! Instead,
the compiler resolves the calls at compile-time and calls only the
“local” version of the function. Notice that the same is true for
the constructor (as described earlier), but in the constructor’s case the
type information wasn’t available, whereas in the destructor the
information (that is, the VPTR) is there, but is isn’t
reliable.