15.10.5. Mecanismo virtual en los destructores

Hay algo que sucede durante la destrucción que no se espera de manera intuitiva. Si se está dentro de una función miembro y se llama a una función virtual, esa función es ejecutada usando el mecanismo de la ligadura dinámica. Esto no es verdad con los destructores, virtuales o no. Dentro de un destructor, sólo se llama a la función miembro "local"; el mecanismo virtual es ignorado.

//: 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;
} ///:~

Listado 15.15. C15/VirtualsInDestructors.cpp


Durante la llamada al destructor virtual, no se llama a Derived::f(), incluso aunque f() es virtual.

¿A qué es debido ésto? Supongamos que fuera usado el mecanismo virtual dentro del destructor. Entonces sería posible para la llamada virtual resolver una función que está "lejana" (más derivada) en la jerarquía de herencia que el destructor actual. Pero los destructores son llamados de "afuera a dentro" (desde el destructor más derivado hacia el destructor de la clase base), por lo que la llamada actual a la función puede intentar acceder a fragmentos de un objeto que !ya ha sido destruido! En vez de eso, el compilador resuelve la llamada en tiempo de compilación y llama sólo a la versión local de la función. Hay que resaltar que lo mismo es también verdad para el constructor (como se explicó anteriormente), pero en el caso del constructor el tipo de información no estaba disponible, mientras que en el destructor la información está ahí (es decir, el VPTR) pero no es accesible.