Es importante conocer el orden de las llamadas de los constructores y destructores de un objeto con varios subobjetos. El siguiente ejemplo muestra cómo funciona:
//: C14:Order.cpp // Constructor/destructor order #include <fstream> using namespace std; ofstream out("order.out"); #define CLASS(ID) class ID { \ public: \ ID(int) { out << #ID " constructor\n"; } \ ~ID() { out << #ID " destructor\n"; } \ }; CLASS(Base1); CLASS(Member1); CLASS(Member2); CLASS(Member3); CLASS(Member4); class Derived1 : public Base1 { Member1 m1; Member2 m2; public: Derived1(int) : m2(1), m1(2), Base1(3) { out << "Derived1 constructor\n"; } ~Derived1() { out << "Derived1 destructor\n"; } }; class Derived2 : public Derived1 { Member3 m3; Member4 m4; public: Derived2() : m3(1), Derived1(2), m4(3) { out << "Derived2 constructor\n"; } ~Derived2() { out << "Derived2 destructor\n"; } }; int main() { Derived2 d2; } ///:~
Listado 14.7. C14/Order.cpp
Primero, se crea un objeto ofstream para enviar la salida a un archivo. Entonces, para no teclear tanto y demostrar la técnica de las macros que será sustituida por otra mucho más mejorada en el capítulo 16, se crea una para construir varias clases que utilizan herencia y composición. Cada constructor y destructor escribe información en el archivo de salida. Fíjense que los constructores no son constructores por defecto; cada uno tiene un parámetro del tipo int. Y además, el argumento no tiene nombre; la única razón de su existencia es forzar la llamada al constructor en la lista de inicializadores del constructor. (Eliminando el identificador evita que el compilador informe con mensajes de advertencia)
La salida de este programa es
Base1 constructor Member1 constructor Member2 constructor Derived1 constructor Member3 constructor Member4 constructor Derived2 constructor Derived2 destructor Member4 destructor Member3 destructor Derived1 destructor Member2 destructor Member1 destructor Base1 destructor
omo puede observar, la construcción empieza desde la raíz de la jerarquía de clases y en cada nivel, el constructor de la clase base se ejecuta primero, seguido por los constructores de los objetos miembro. Los destructores son llamados exactamente en el orden inverso que los constructores -esto es importante debido a los problemas de dependencias (en el constructor de la clase derivada o en el destructor, se debe asumir que el subobjeto de la clase base esta todavía disponible para su uso, y ha sido construido - o no se ha destruido todavía).
También es interesante que el orden de las llamadas al constructor para los objetos miembro no afecten para nada el orden de las llamadas en la lista de inicializadores de un constructor. El orden es determinado por el orden en que los objetos miembros son declarados en la clase. Si usted pudiera cambiar el orden del constructor en la lista de inicializadores de un constructor, usted podría tener dos secuencias diferentes de llamada en dos constructores diferentes, pero el destructor no sabría como invertir el orden para llamarse correctamente y nos encontraríamos con problemas de dependencias.