Técnica manejador-cuerpo
Ejemplo:
El programa muestra un ejemplo esquemático de aplicación de la técnica manejador-cuerpo en la que un manejador sirve para acceder a diversos objetos que responden a la misma interfaz. Por supuesto se trata de un ejemplo esquemático y muy incompleto, pero ilustra claramente los principios de esta técnica.
#include <iostream>
using namespace std;
class Body {
// Superclase abstracta
friend class Handle;
protected:
virtual void funcB() =0;
virtual ~Body(); // destructor virtual!!
};
Body::~Body() { cout << "Destruyendo Objeto Body\n"; }
class B1 : public Body { // implementación-1
friend class Handle;
void funcB() { cout << "Objeto B1\n"; }
~B1() { cout << "Destruyendo Objeto B1\n"; }
};
class B2 : public Body { // implementación-2
friend class Handle;
void funcB() { cout << "Objeto B2\n"; }
~B2() { cout << "Destruyendo Objeto B2\n"; }
};
class Handle {
// manejador
public:
Handle (int n=0); // constructor por
defecto
void funcH();
// método público
~Handle();
// destructor
private:
Body* bPtr;
};
void Handle::funcH() { bPtr->funcB(); }
Handle::Handle(int n) { // definición del constructor
if (n == 0) bPtr = new B1;
else bPtr = new B2;
}
Handle::~Handle() { // definición del destructor
cout << "Destruyendo Handle\n";
delete bPtr;
// L.42:
}
int main() {
// =================
{
Handle h1(1);
// M2:
h1.funcH();
// M3:
Handle h2;
// M4:
h2.funcH();
// M5:
}
// M6:
return 0;
}
Salida:
Objeto B2
Objeto B1
Destruyendo Handle
Destruyendo Objeto B1
Destruyendo Objeto Body
Destruyendo Handle
Destruyendo Objeto B2
Destruyendo Objeto Body
Comentario:
El ejemplo muestra una superclase abstracta Body, de la que derivan dos implementaciones distintas: B1 y B2. El manejador Handle contiene un método público funcH que accede a las funciones de la implementación a través de un puntero bPtr a la superclase. Observe que es el propio manejador el que crea instancias de la implementación a través de su constructor, y el que se encarga después de destruirlas con su destructor.
Las salidas 1 y 2 son debidas a las sentencias M3 y M5. El resto de salidas se originan al salir de ámbito los objetos automáticos h1 y h2, y constituyen una magnífica muestra del proceso seguido en la destrucción de objetos.
Al llegar a M6 son invocados automáticamente los destructores ~Handle() de los objetos h1 y h2, que invocan a su vez a la destrucción del objeto señalado por el puntero bPtr.
La sentencia L.42:
delete bPtr; // L.42:
invoca a su vez al destructor del objeto ( 4.9.20a), de forma que son invocados los destructores ~B1() y ~B2(). A continuación, como las clases B1 y B2 no disponen de ninguna versión sobrecargada del operador delete(), se invoca la versión global ::operator delete(bPtr). Recordemos que en la destrucción de objetos pertenecientes a jerarquías de clases, los destructores son invocados en orden inverso en que fuero invocados los constructores, resultando que las invocaciones de los destructores ~B1() y ~B2() son seguidas de sendas invocaciones al destructor ~Body() de la superclase.
Observe que la única acción que puede realizar explícitamente el usuario sobre los objetos Body es la invocación de la función Handle::funcH(). El resto de acciones, incluyendo la creación de objetos Bn y su destrucción, son realizadas automáticamente por el manejador Handle a través de sus constructores y destructores.