Las soluciones a los ejercicios se pueden encontrar en el documento electrónico titulado «The Thinking in C++ Annotated Solution Guide», disponible por poco dinero en www.BruceEckel.com.
Modifique Car.cpp para que también herede de una clase llamada Vehicle, colocando en Vehicle las funciones miembro apropiadas (es decir, invéntese algunas funciones miembro). Añada a Vehicle un constructor que no sea el constructor por defecto, al que deberá llamar dentro del constructor de Car.
Cree dos clases, A y B, con constructores por defecto que se anuncien a sí mismos. Herede una nueva clase llamada C de A y cree un objeto miembro de B en C, pero no cree ningún constructor para C. Cree un objeto de la clase C y observe los resultados.
Cree una jerarquía de clases de tres niveles con constructores por defecto y con destructores, que se anuncien todos ellos en cout. Compruebe que, para un objeto del tipo más derivado, se llama automáticamente a los tres constructores y destructores. Explique el orden en que se realizan las llamadas.
Modifique Combined.cpp para añadir otro nivel de herencia y un nuevo objeto miembro. Añada código para mostrar cuándo se llama a los constructores y destructores.
En Combined.cpp, cree una clase D que herede de B y tenga un objeto miembro de la clase C. Añada código para mostrar cuándo se llama a los constructores y destructores.
Modifique Order.cpp para añadir otro nivel de herencia, Derived3, con objetos miembro de las clases Member4 y Member5. Siga la traza de la salida del programa.
En NameHiding.cpp, compruebe que en Derived2, Derived3 y Derived4 no está disponible ninguna de las versiones de f() de la clase base.
Modifique NameHiding.cpp añadiendo a Base tres funciones sobrecargadas llamadas h(), y muestre que redefinir una de ellas en una clase derivada oculta las demás.
Herede una clase StringVector de vector<void*> y redefina las funciones miembro push_back() y operator[] para que acepten y devuelvan string*. ¿Qué ocurre si intenta hacer push_back() de un void*?
Escriba una clase que contenga un long y utilice la sintaxis de llamada a pseudoconstructor en el constructor para inicializar el long.
Cree una clase llamada Asteroid. Utilice la herencia para especializar la clase PStash del Capítulo 13 (PStash.h y PStash.cpp) de modo que acepte y devuelva punteros a Asteroid. Modifique también PStashTest.cpp para probar sus clases. Cambie la clase para que PStash sea un objeto miembro.
Repita el ejercicio 11 con un vector en vez de un PStash.
En SynthesizedFunctions.cpp, modifique Chess para darle un constructor por defecto, un constructor de copia y un operador de asignación. Demuestre que los ha escrito correctamente.
Cree dos clases llamadas Traveler y Pager sin constructores por defecto, pero con constructores que reciban un argumento de tipo string, que simplemente copian en una variable string interna. Para cada clase, escriba correctamente el constructor de copia y el operador de asignación. Ahora herede una clase BusinessTraveler de Traveler y dele un objeto miembro de tipo Pager. Escriba correctamente el constructor por defecto, un constructor que reciba un argumento string, un constructor de copia y un operador de asignación.
Cree una clase con dos funciones miembro estáticas. Herede de esta clase y redefina una de las funciones miembro. Muestre que la otra queda oculta en la clase derivada.
Busque más funciones miembro de ifstream. En FName2.cpp, pruébelas con el objeto file.
Utilice la herencia privada y la protegida para crear dos nuevas clases a partir de una clase base. Después intente hacer upcast de los objetos de las clases derivadas a la clase base. Explique lo que ocurre.
En Protected.cpp, añada a Derived una función miembro que llame al miembro protegido read() de Base.
Cambie Protected.cpp para que Derived utilice herencia protegida. Compruebe si puede llamar a value() para un objeto Derived.
Cree una clase llamada SpaceShip con un método fly(). Herede Shuttle de SpaceShip y añádale un método land(). Cree un nuevo Shuttle, hágale upcast mediante un puntero o una referencia a SpaceShip e intente llamar al método land(). Explique los resultados.
Modifique Instrument.cpp para añadir un método prepare() a Instrument. Llame a prepare() dentro de tune().
Modifique Instrument.cpp para que play() muestre un mensaje por cout, y que Wind redefina play() para mostrar un mensaje diferente por cout. Ejecute el programa y explique por qué probablemente no querría este comportamiento. Ahora ponga la palabra reservada virtual (que aprenderá en el Capítulo 15) delante de la declaración de play() en Instrument y observe el cambio en el comportamiento.
En CopyConstructor.cpp, herede una nueva clase de Child y dele un Member m. Escriba un constructor apropiado, un constructor de copia, un operator= y un operator<< para ostream, y pruebe la clase en main().
Tome el ejemplo CopyConstructor.cpp y modifíquelo añadiendo su propio constructor de copia a Child sin llamar al constructor de copia de la clase base, y vea qué ocurre. Arregle el problema haciendo una llamada explícita apropiada al constructor de copia de la clase base en la lista de inicialización del constructor de copia de Child.
Modifique InheritStack2.cpp para utilizar un vector<string> en vez de un Stack.
Cree una clase Rock con un constructor por defecto, un constructor de copia, un operador de asignación y un destructor, que anuncien todos ellos por cout que han sido llamados. En main(), cree un vector<Rock> (es decir, que guarde objetos Rock por valor) y añada varios Rock. Ejecute el programa y explique la salida que obtiene. Fíjese en si se llama a los destructores de los objetos Rock del vector. Ahora repita el ejercicio con un vector<Rock*>. ¿Es posible crear un vector<Rock&>?
Este ejercicio crea el patrón de diseño llamado proxy. Empiece con una clase base Subject y dele tres funciones: f(), g() y h(). Ahora herede de Subject una clase Proxy y dos clases Implementation1 e Implementation2. Proxy debería contener un puntero a un Subject, y todas las funciones miembro de Proxy deberían limitarse a hacer las mismas llamadas a través del puntero a Subject. El constructor de Proxy recibe un puntero a un Subject que se instala en el Proxy (normalmente mediante el constructor). En main(), cree dos objetos Proxy diferentes que utilicen las dos implementaciones distintas. Ahora modifique Proxy para que pueda cambiar de implementación dinámicamente.
Modifique ArrayOperatorNew.cpp del Capítulo 13 para mostrar que, si hereda de Widget, la reserva de memoria sigue funcionando correctamente. Explique por qué la herencia en Framis.cpp del Capítulo 13 no funcionaría correctamente.
Modifique Framis.cpp del Capítulo 13 heredando de Framis y creando nuevas versiones de new y delete para su clase derivada. Demuestre que funcionan correctamente.