Metodología de la Programación II Bloque práctico 1: C++ 1: Programación modular, herencia simple y polimorfismo. En esta práctica utilizaremos las capacidades de programación orientada a objetos, tanto básicas como avanzadas, de que dispone C++. El objetivo de la práctica es programar un lienzo y figuras que se puedan pintar utilizando herencia y polimorfismo. 1) Programar un lienzo y figuras dibujables Un Lienzo es una matriz de puntos de imagen (píxels) de dos dimensiones al que se le pueden poner los píxels de un color determinado (un entero). Un lienzo se puede rellenar de un color, con lo que todos los píxels del lienzo tendrían dicho valor. Un lienzo, finalmente, se puede mostrar por pantalla, traduciendo según el tipo de Lienzo el entero a una representación. Se debe implementar, asimismo, una clase heredada de Lienzo (LienzoCaracter) , cuya representación sea el entero interpretado como un carácter ASCII. Para pintar en este Lienzo, vamos a construir unas figuras que sepan como pintarse en un lienzo, teniendo en cuenta que si el dibujo se sale de los límites del mismo no se pinten los píxeles que se salen del lienzo (es decir, si la figura se sale del lienzo, no da error, sólo visualiza la parte que cae dentro del mismo). Una figura contiene una posición de origen expresada por dos enteros que determinan la posición del eje x y el eje y. Esta posición es una clase aparte contenida por la figura. Una figura debe tener un método que devuelva una cadena de caracteres ( char * de C, no string de C++) con la descripción del tipo de figura y su contenido. Una figura tiene un color determinado por un entero. Las figuras disponibles son: Punto: Posición y color. Circulo: Centro (una posición) , radio (entero) y color. Linea : Posición inicial, posición final y color. Bitmap : Posición inicial (esquina superior izquierda), ancho, alto ,contenido y color. Metodología de la Programación II Notas sobre los métodos de Dibujo de cada figura: Circulo y Linea deberán calcular la posición de los píxels en el lienzo usando funciones trigonométricas y el número PI (disponible en la biblioteca math.h). Ejemplo: dibujar un Circulo de radio 3 y color '#' ##### ## ## # # # # # # ## ## ##### Ejemplo: dibujar una Linea que vaya de la posición(0,0) a la posición(5,5) en color '.' . . . . . . . . Bitmap se construye como una cadena que contiene unos ("1") en las posiciones que se quiere pintar y "0" en las no pintables (bitmap monocromo). Un ejemplo de bitmap de alto 3 y ancho tres es el siguiente: Contenido del bitmap: "001001001" Bitmap dibujado con el color '*': " * * *" donde " " serian pixels no dibujados y * el píxel dibujado en el color * Estas figuras deben contener en una superclase todas aquellas características que les sean comunes. Finalmente, debe quedar compilada como una biblioteca estática, llamada LibFiguras, que se pueda enlazar a otros programas. Por comodidad y para los ejemplos programados que siguen, cree un archivo de cabecera Libfiguras.hpp, que incluya todas las cabeceras creadas para los módulos de esta biblioteca. Metodología de la Programación II Compile y enlace el código siguiente en un proyecto diferente que utilice la librería creada. Compruebe que su librería obtiene la salida deseada. En caso contrario, modifique su librería para que funcione correctamente. PruebaLib.Cpp int main(int argc, char *argv[]) { LienzoCaracter z(15,12); Posicion pos1(1,1),pos2(5,5),pos3(8,8); Punto p(pos1,'*'),p1(pos2,'+'); Circulo c(pos2,4,'^'); Linea l(pos1,pos3,'.'); char* contenido =strdup("001001001"); Bitmap b(Posicion(2,2),contenido,3,3,'@'); z.rellenar(' '); // Pinta dos puntos, un bitmap p.pintar(&z); // y un circulo de radio 4 p1.pintar(&z); b.pintar(&z); c.pintar(&z); z.mostrar(); cout << p.descripcion()<< "\n"; cout << b.descripcion()<< "\n"; system("PAUSE"); //Limpia el lienzo z.rellenar(); //Dibuja un circulo y una linea c.setRadio(5); //cambio radio c.setPos(pos3);//cambio posicion c.pintar(&z); l.pintar(&z); z.mostrar(); cout << c.descripcion()<< "\n"; cout << l.descripcion()<< "\n"; system("PAUSE"); c.setColor('#'); z.rellenar(); c.setRadio(3); c.pintar(&z); z.mostrar(); //Ejemplo del circulo system("PAUSE"); //Ejemplo de la Linea l.setColor('.'); z.rellenar(); l.pintar(&z); z.mostrar(); system("PAUSE"); // Ejemplo de Polimorfismo Figura *f; Lienzo *li; f = &l; li = &z; f->pintar(li); li->mostrar(); system("PAUSE"); return EXIT_SUCCESS; } Metodología de la Programación II Salida Esperada * ^^^^^ ^^@ ^^ ^^ @ ^^ ^ @ ^ ^ + ^ ^ ^ ^^ ^^ ^^ ^^ ^^^^^ Punto:(1,1), color:42 Bitmap:(2,2), color:64, contenido:001001001 Presione una tecla para continuar . . . . . . ^^^^^ .^^ ^^ ^. ^^ . ^ . ^ . ^ ^^ ^ ^^^ ^^ ^^^^^ Circulo:(8,8):5, color:94 Linea:(1,1),(8,8), color:46 Presione una tecla para continuar . . . ##### ## ## # # # # # # ## ## ##### Presione una tecla para continuar . . . . . . . . . . . Presione una tecla para continuar . . . . . . . . . . . Nota: Se han eliminado algunos saltos de línea antes de cada "presione....." para que quepa el ejemplo. Metodología de la Programación II 2) Conseguir que Figura y Lienzo muestren comportamiento polimórfico dinámico: polimorfismo. un Realizar un programa de prueba, que cree figuras de varios tipos y las meta en un array de referencias. Recorrer posteriormente el array con un bucle llamando al método pintar (por ejemplo si el array se llama tabla, tabla[i]->pintar(l), siendo Lienzo *l). Tanto Lienzo como Figura deben mostrar un comportamiento polimórfico. Todos aquellos métodos en Lienzo y Figura que sean comunes a las subclases deben tener un comportamiento polimórfico. Completa el programa llamando a cada uno de estos métodos de la misma forma que el programa solicitado usando pintar(Lienzo *l). 3) Hacer que Figura y Lienzo sean clases abstractas Consideramos que en nuestro sistema, un Lienzo y una Figura no se deben poder instanciar como objetos. Realice las modificaciones necesarias para que el compilador restrinja la instanciación de la clase Lienzo y Figura. Realice un programa de prueba que instancie la clase Figura y compruebe que el compilador da un error. Si eliminamos la posibilidad de crear objetos de la clase Figura, ¿es esto equivalente a quitar la clase de nuestro diseño? (responda a estas preguntas en comentarios en el propio programa de prueba) 4) Destructores. Queremos que todas nuestras clases tengan un destructor que muestre por pantalla el mensaje: “DESTRUCTOR: objeto>]” <NombreDeClase>[ <descripción del Es decir: la palabra DESTRUCTOR seguida del nombre de la clase a la que pertenece el objeto que se está destruyendo y, en caso de que la clase sea una figura concreta, de la descripción del objeto que se destruye. En caso de ser necesario, el destructor deberá liberar la memoria que se ha reservado para el objeto. (¡Ojo con las cadenas dinámicas!). Haremos que estos mensajes se muestren por pantalla en base a una constante definida con el precompilador: #define DEPURACION … #ifdef DEPURACION … Código para mostrar el mensaje … #endif Metodología de la Programación II De modo que, si no se define la constante, la biblioteca de clases LibFiguras no muestre mensajes cuando se ejecuten los destructores. Realice un programa de prueba que genere un lienzo y una figura de cada clase y que posteriormente los borre (delete) . Deberá mostrar los mensajes indicados por cada clase. Instrucciones de Entrega La práctica deberá dejarse comprimida con winrar con el nombre: Practica1_1_xxx.rar en la cuenta de usuario. donde xxx es el código de usuario asociado. La práctica deberá contener dos directorios (LibFiguras y PruebaFiguras), en LibFiguras estarán todas las clases de la librería, con un fichero .hpp y .cpp por cada clase y un proyecto denominado Libfiguras para la generación de la librería estática. En el otro directorio estarán todas las pruebas a realizar sobre la librería en .cpp independientes con el numero del apartado que prueban: libPru_1,libpru_2,etc.... Las fechas de entrega serán desde el 13 al 25 de defenderlas en clase de la siguiente forma: - Noviembre, siendo necesario Dejar el fichero comprimido en la cuenta. En el ordenador del profesor probar todos los ficheros de prueba. Si funcionan adecuadamente se revisarán las librerías y programas de prueba. En caso de encontrarse errores se permitirá la reentrega dentro de fecha En caso de errores graves no se considera apta. Si la entrega final tiene errores leves, la calificación podrá ser del 50% ó 75% de la parte que le corresponda a la práctica. Esta nota será validada cuando se realice el examen de modificación hasta entonces la nota no será definitiva. Es necesario superar todas las prácticas y haber asistido a un 70% de las clases para tener apta la parte práctica de la asignatura, en caso contrario se puede optar por examen final práctico.