10.7. Ejercicios

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.

  1. Cree una función con una variable estática que sea un puntero (con un argumento por defecto igual cero). Cuando la función que realice la llamada proporcione un valor para ese argumento se usará para apuntar al principio de un array de int. Si se llama a la función con el argumento cero (utilizando el argumento por defecto), la función devuelve el siguiente valor del array, hasta que llegue a un valor -1 en el array (que actuará como señal de final). Experimente con esta función en main().

  2. Cree una función que devuelva el siguiente valor de una serie de Fibonacci cada vez que sea llamada. Añada un argumento que de tipo bool con valor por defecto false tal que cuando el argumento valga true «reinicie» la función al principio de la serie de Fibonacci. Experimente con esta función en main().

  3. Cree una clase que contenga un array de int. Especifique la dimensión del array utilizando static const int dentro de la clase. Añada una variable const int e inicialícela en la lista de inicialización del constructor. Haga al constructor inline. Añada un atributo static int e inicialícelo a un valor específico. Añada un método estático que imprima el atributo estático. Añada un miembro inline llamado print() que imprima todos los valores del array y que llame al método estático. Experimente con esta clase en main().

  4. Cree una clase llamada Monitor que mantenga el registro del número de veces que ha sido llamado su método incident(). Añada un método print() que muestre por pantalla el número de incidentes. Ahora cree una función global (no un método) que contenga un objeto estático Monitor. Cada vez que llame a la función debe llamar a incident(), después al método print() para sacar por pantalla el contador de incidentes. Experimente con la función en main().

  5. Modifique la clase Monitor del Ejercicio 4 de forma que pueda decrementar (decrement()) el contador de incidentes. Cree una clase llamada Monitor2 que tome como argumento del constructor un puntero a Monitor1, y que almacene ese puntero y llame a incident() y print(). En el destructor para Monitor2, llame a decrement() y print(). Cree ahora un objeto estático de Monitor2 dentro de una función. Dentro de main(), experimente llamando y no llamando a la función para ver qué pasa con el destructor de Monitor2.

  6. Cree un objeto global de clase Monitor2 y vea qué sucede.

  7. Cree una clase con un destructor que imprima un mensaje y después llame a exit(). Cree un objeto global de esa clase y vea qué pasa.

  8. En StaticDestructors.cpp, experimente con el orden de llamada de los constructores y destructores llamando a f() y g() dentro de main() en diferentes órdenes. ¿Su compilador inicializa los objetos de la forma correcta?

  9. En StaticDestructors.cpp, pruebe el manejo de errores por defecto de su implementación convirtiendo la definición original de out dentro de una declaración extern, y poniendo la definición real después de la definición de a (donde el constructor de Obj manda información a out). Asegúrese que no hay ningún otro programa importante funcionando en su máquina cuando ejecute el código o que su máquina maneje las faltas robustamente.

  10. Pruebe que las variables estáticas de fichero en los archivos de cabecera no chocan entre sí cuando son incluidas en más de un archivo cpp.

  11. Cree una única clase que contenga un int, un constructor que inicialice el int con su argumento, un método que cambie el valor del int con su argumento y una función print() que muestre por pantalla el int. Coloque su clase en un archivo de cabecera e incluya dicho archivo en dos archivos cpp. En uno de ellos cree una instancia de la clase y en la otra declare ese identificador como extern y pruebe dentro de main(). Recuerde, debe enlazar los dos archivos objeto o de lo contrario el enlazador no encontrará el objeto.

  12. Cree la instancia del objeto del Ejercicio 11 como static y verifique que, debido a eso, el enlazador es incapaz de encontrarla.

  13. Declare una función en un archivo de cabecera. Defina la función en un archivo cpp y llámela desde main() en un segundo archivo cpp. Compile y verifique que funciona. Ahora cambie la definición de la función de forma que sea static y verifique que el enlazador no puede encontrarla.

  14. Modifique Volatile.cpp del Capítulo 8 para hacer que comm::isr() funcione realmente como una rutina de servicio de interrupción. Pista: una rutina de servicio de interrupción no toma ningún argumento.

  15. Escriba y compile un único programa que utilice las palabras clave auto y register.

  16. Cree un archivo de cabecera que contenga un espacio de nombres. Dentro del espacio de nombres cree varias declaraciones de funciones. Cree ahora un segundo archivo de cabecera que incluya el primero y continúe el espacio de nombres, añadiendo varias declaraciones de funciones más. Cree ahora un archivo cpp que incluya el segundo archivo de cabecera. Cambie su espacio de nombres a otro nombre (más corto). Dentro de una definición de función, llame a una de sus funciones utilizando la resolución de ámbito. Dentro de una definición de función separada, escriba una directiva using para introducir su espacio de nombres en el ámbito de esa función, y demuestre que no necesita utilizar la resolución de ámbito para llamar a las funciones desde su espacio de nombres.

  17. Cree un archivo de cabecera con un espacio de nombres sin nombre. Incluya la cabecera en dos archivos cpp diferentes y demuestre que un espacio sin nombre es único para cada :unidad de traducción.

  18. Utilizando el archivo de cabecera del Ejercicio 17, demuestre que los nombres de un espacio de nombres sin nombre están disponibles automáticamente en una :unidad de traducción sin calificación.

  19. Modifique FriendInjection.cpp para añadir una definición para la función amiga y para llamar a la función desde main().

  20. En Arithmetic.cpp, demuestre que la directiva using no se extiende fuera de la función en la que fue creada.

  21. Repare el problema de OverridingAmbiguity.cpp, primero con resolución de ámbito y luego, con una declaración using que fuerce al compilador a escojer uno de los nombres de función idénticos.

  22. En dos archivos de cabecera, cree dos espacios de nombres, cada uno conteniendo una clase (con todas las definiciones inline) con idéntico nombre que el del otro espacio de nombres. Cree un archivo cpp que incluya ambos archivos. Cree una función y, dentro de la función, utilice la directiva using para introducir ambos espacios de nombres. Pruebe a crear un objeto de la clase y vea que sucede. Haga las directivas using globales (fuera de la función) para ver si existe alguna diferencia. Repare el problema usando la resolución de ámbito, y cree objetos de ambas clases.

  23. Repare el problema del Ejercicio 22 con una declaración using que fuerce al compilador a escojer uno de los nombres de clase idénticos.

  24. Extraiga las declaraciones de espacios de nombres de BobsSuperDuperLibrary.cpp y UnnamedNamespaces.cpp y póngalos en archivos separados, dando un nombre al espacio de nombres sin nombre en el proceso. En un tercer archivo de cabecera, cree un nuevo espacio de nombres que combine los elementos de los otros dos espacios de nombres con declaraciones using. En main(), introduzca su nuevo espacio de nombres con una directiva using y acceda a todos los elementos de su espacio de nombres.

  25. Cree un archivo de cabecera que incluya <string> y <iostream> pero que no use ninguna directiva using ni ninguna declaración using. Añada guardas de inclusión como ha visto en los archivos de cabecera del libro. Cree una clase con todas las funciones inline que muestre por pantalla el string. Cree un archivo cpp y ejercite su clase en main().

  26. Cree una clase que contenga un static double y long. Escriba un método estático que imprima los valores.

  27. Cree una clase que contenga un int, un constructor que inicialice el int con su argumento, y una función print() que muestre por pantalla el int. Cree ahora una segunda clase que contenga un objeto estático de la primera. Añada un método estático que llame a la función print() del objeto estático. Ejercitu su clase en main().

  28. Cree una clase que contenga un array estático de int constante y otro no constante. Escriba métodos estáticos que impriman los arrays. Experimente con su clase en main().

  29. Cree una clase que contenga un string, con un constructor que inicialice el string a partir de su argumento, y una función print() que imprima el string. Cree otra clase que contenga un array estático, tanto constante como no constante, de objetos de la primera clase, y métodos estáticos para imprimir dichos arrays. Experimente con la segunda clase en main().

  30. Cree una struct que contenga un int y un constructor por defecto que inicialice el int a cero. Haga ese struct local a una función. Dentro de dicha función, cree un array de objetos de su struct y demuestre que cada int del array ha sido inicializado a cero automáticamente.

  31. Cree una clase que represente una conexión a impresora, y que sólo le permita tener una impresora.

  32. En un archivo de cabecera, cree una clase Mirror que contiene dos atributos: un puntero a un objeto Mirror y un bool. Déle dos constructores: el constructor por defecto inicializa el bool a true y el puntero a Mirror a cero. El segundo constructor toma como argumento un puntero a un objeto Mirror, que asigna al puntero interno del objeto; pone el bool a false. Añada un método test(): si el puntero del objeto es distinto de cero, devuelve el valor de test() llamado a través del puntero. Si el puntero es cero, devuelve el bool. Cree ahora cinco archivos cpp, cada uno incluyendo la cabecera Mirror. El primer archivo cpp define un objeto Mirror global utilizando el constructor por defecto. El segundo archivo declara el objeto del primer archivo como extern, y define un objeto Mirror global utilizando el segundo constructor, con un puntero al primer objeto. Siga haciendo lo mismo hasta que llegue al último archivo, que también contendrá una definición de objeto global. En este archivo, main() debe llamar a la función test() e informar del resultado. Si el resultado es true, encuentre la forma de cambiar el orden de enlazado de su enlazador y cámbielo hasta que el resultado sea false.

  33. Repare el problema del Ejercicio 32 utilizando la técnica uno mostrada en este libro.

  34. Repare el problema del Ejercicio 32 utilizando la técnica dos mostrada en este libro.

  35. Sin incluir ningún archivo de cabecera, declare la función puts() de la Librería Estándar de C. Llame a esa función desde main().