12.8. 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 clase sencilla con un operador sobrecargado ++. Intente llamar a este operador en la forma prefija y postfija y vea qué clase de advertencia obtiene del compilador.

  2. Cree una clase sencilla que contenga un int y sobrecargue el operador + como un método. Cree también un método print() que tome un ostream& como un argumento y lo imprima a un ostream&. Pruebe su clase para comprobar que funciona correctamente.

  3. Añada un operador binario - al ejercicio 2 como un método. Demuestre que puede usar sus objetos en expresiones complejas como a + b -c.

  4. Añada un operador ++ y otro -- al ejercicio 2, ambos con las versiones prefijas y postfijas, tales que devuelvan el objeto incrementado o decrementado. Asegúrese de que la versión postfija devuelve el valor correcto.

  5. Modifique los operadores de incremento y decremento del ejercicio 4 para que la versión prefija devuelva una referencia no const y la postfija devuelva un objeto const. Muestre que funcionan correctamente y explique porqué esto se puede hacer en la práctica.

  6. Cambie la función print() del ejercicio2 para que use el operador sobrecargado << como en IostreamOperatorOverloading.cpp.

  7. Modifique el ejercicio 3 para que los operadores + y - no sean métodos. Demuestre que todavía funcionan correctamente.

  8. Añada el operador unario - al ejercicio 2 y demuestre que funciona correctamente.

  9. Cree una clase que contenga un único private char. Sobrecargue los operadores de flujos de entrada/salida << y >> (como en IostreamOperatorOverloading.cpp) y pruébelos. Puede probarlos con fstreams, stringstreams y cin y cout.

  10. Determine el valor constante ficticio que su compilador pasa a los operadores postfijos ++ y --.

  11. Escriba una clase Number que contenga un double y añada operadores sobrecargados para +, -, *, / y la asignación. Elija los valores de retorno para estas funciones para que las expresiones se puedan encadenar y que sea eficiente. Escriba una conversión automática de tipos operator int().

  12. Modifique el ejercicio 11 para que use la optimización del valor de retorno, si todavía no lo ha hecho.

  13. Cree una clase que contenga un puntero, y demuestre que si permite al compilador sintetizar el operador = el resultado de usar ese operador serán punteros que estarán solapados en la misma ubicación de memoria. Ahora arregle el problema definiendo su propio operador = y demuestre que corrige el solapamiento. Asegúrese que comprueba la auto-asignación y que maneja el caso apropiadamente.

  14. Escriba una clase llamada Bird que contenga un miembro string y un static int. En el constructor por defecto, use el int para generar automáticamente un identificador que usted construya en el string junto con el nombre de la clase(Bird #1, Bird #2, etc). Añada un operador <;< para flujos de salida para imprimir los objetos Bird-Escriba un operador de asignación = y un constructor de copia. En main() verifique que todo funciona correctamente.

  15. Escriba una clase llamada BirdHouse que contenga un objeto, un puntero y una referencia para la clase Bird del ejercicio 14. El constructor debería tomar 3 Birds como argumentos. Añada un operador << de flujo de salida para BirdHouse. Deshabilite el operador de asignación = y el constructor de copia. En main() verifique que todo funciona correctamente.

  16. Añada un miembro de datos int a Bird y a BirdHouse en el ejercicio 15. Añada operadores miembros +, -, * y / que usen el miembro int para realizar las operaciones en los respectivos miembros. Verifique que funcionan.

  17. Repita el ejercicio 16 usando operadores no miembro.

  18. Añada un operador - a SmartPointer.cpp y a NestedSmartPointer.cpp.

  19. Modifique CopyingVsInitialization.cpp para que todos los constructores impriman un mensaje que explique qué está pasando. Ahora verifique que las dos maneras de llamar al constructor de copia (la de asignación y la de paréntesis) son equivalentes.

  20. Intente crear un operador no miembro = para una clase y vea qué clase de mensaje del compilador recibe.

  21. Cree una clase con un operador de asignación que tenga un segundo argumento, un string que tenga un valor por defecto que diga op = call. Cree una función que asigne un objeto de su clase a otro y muestre que su operador de asignación es llamado correctamente.

  22. En CopyingWithPointers.cpp elimine el operador = en DogHouse y muestre que el operador = sintetizado por el compilador copia correctamente string pero es simplemente un alias del puntero Dog.

  23. En ReferenceCounting.cpp añada un static int y un int ordinario como atributos a Dog y a DogHouse. En todos los constructores para ambas clases, incremente el static int y asigne el resultado al int ordinario para mantener un seguimiento del número de objetos que están siendo creados. Haga las modificaciones necesarias para que todas las sentencias de impresión muestren los identificadores int de los objetos involucrados.

  24. Cree una clase que contenga un string como atributo. Inicialice el string en el constructor, pero no cree un constructor de copia o un operador =. Haga una segunda clase que tenga un atributo de su primera clase; no cree un constructor de copia o un operador = para esta clase tampoco. Demuestre que el constructor de copia y el operador = son sintetizados correctamente por el compilador.

  25. Combine las clases en OverloadingUnaryOperators.cpp y en Integer.cpp.

  26. Modifique PointerToMemmberOperator.cpp añadiendo dos nuevas funciones miembro a Dog que no tomen argumentos y devuelvan void. Cree y compruebe un operador sobrecargado ->* que funcione con sus dos nuevas funciones.

  27. Añada un operador ->* a NestedSmartPointer.cpp.

  28. Cree dos clases, Apple y Orange. En Apple, cree un constructor que tome una Orange como argumento. Cree una función que tome un Apple y llame a esa función con una una Orange para demostrar que funciona. Ahora haga explícito el constructor de Apple para demostrar que así se evita la conversión automática de tipos. Modifique la llamada a su función para que la la conversión se haga explícitamente y de ese modo, funcione.

  29. Añada un operador global * a ReflexivityInOverloading.cpp y demuestre que es reflexivo.

  30. Cree dos clases y un operador + y las funciones de conversión de tal manera que la adicción sea reflexiva para las dos clases.

  31. Arregle TypeConversionFanout.cpp creando una función explícita para realizar la conversión de tipo, en lugar de uno de los operadores de conversión automáticos.

  32. Escriba un código simple que use los operadores +, -, *, / para double. Imagine cómo el compilador genera el codigo ensamblador y mire el ensamblador que se genera en realidad para descubrir y explicar qué está ocurriendo «bajo el capó».