Hay algo que sucede durante la destrucción que quizá no se espere de entrada. Si se está dentro de una función miembro ordinaria 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 versión «local» de la función miembro; 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, no se llama a Derived::f(), aunque f() sea virtual.
¿A qué se debe esto? Suponga que se usara el mecanismo virtual dentro del destructor. Entonces sería posible que la llamada virtual se resolviera en una función que estuviera «más lejos» (más derivada) en la jerarquía de herencia que el destructor actual. Pero los destructores son llamados «de fuera hacia dentro» (desde el destructor más derivado hacia el destructor de la clase base), por lo que la función a la que realmente se llamara dependería de 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 la información de tipo no estaba disponible, mientras que en el destructor la información está ahí (es decir, el VPTR) pero no es fiable.