Problema 1) NOTAS: i) Se recomienda leer todo el enunciado antes de comenzar a resolver este problema. ii) El apartado c) es opcional. Las restantes partes del examen suman 10 puntos. a) (1,5 puntos) Se desea desarrollar un programa en C++que permita colocar tems rectangulares de tamaos diversos en un contenedor formando hileras. La longitud mxima de las hileras es fija y los tems se aaden colocndolos al final de la ltima hilera hasta que no caben en ella, momento en que se comienza una hilera nueva (para fijar ideas, el contenedor podra ser esta hoja de papel, los tems podran ser las palabras que aparecen en este prrafo y las hileras las lneas que lo forman). Se pide un programa que incluya la estructura de un conjunto de clases que permitan la funcionalidad indicada y la definicin de un mtodo que aade un item al contenedor, colocndolo al final de la ltima hilera o, si no hay espacio, al comienzo de la siguiente. Las hileras tendrn una altura variable para ajustarse a la altura de los itms que contienen. Entre cada dos hileras y entre cada dos tems consecutivos no se dejar ningn espacio. Los tems contenidos en una hilera tendrn la parte ms prxima a la hilera anterior pegada a la misma. La altura de cada hilera ser la mayor de las alturas de los tems que contiene. b) (1,5 puntos) Se desea utilizar el programa anterior (adaptndolo o extendindolo) para programar un visualizador de documentos de texto basado en MFC de acuerdo con las siguientes especificaciones: I. Los documentos no tienen mrgenes superiores, inferiores, izquierdos ni derechos. Los documentos estn formados por un slo prrafo en el que las palabras se alinean a la izquierda, como en el primer prrafo de este enunciado. Las longitudes que se mencionan a partir de aqu se miden en pixels. II. Los prrafos estn formados por palabras. Las palabras corresponden a cadenas de caracteres, implementadas mediante la clase CString de MFC y se dibujan mediante el mtodo CDC::TextOut(int x, int y, CString contenido), en el que los argumentos x e y denotan la posicin del vrtice ms prximo al comienzo del documento donde se va a escribir la cadena de caracteres. Las dimensiones (altura y anchura en pixels) de una cadena de caracteres al dibujarla en la pantalla se obtienen mediante el mtodo CDC::GetTextExtent(CString), que devuelve una estructura (struct) de tipo CSize con atributos cx y cy que son de tipo int. (Nota: Se puede tambin utilizar la subclase CPaintDC de CDC en lugar de esta ltima). Las palabras no estn separadas por ningn espacio (se puede considerar que contienen los espacios en blanco necesarios como caracteres). Se pide un programa que incluya la estructura de un conjunto de clases que permitan la funcionalidad indicada y la definicin de un mtodo que dibuja el documento. c) (opcional, 1,5 puntos) Se pide un programa semejante al del apartado b) anterior (conjunto de clases y mtodo de dibujado) que permita visualizar documentos cuyo contenido est formado por palabras y rectngulos. Para ello se supondr que en la clase CDC se dispone de un mtodo DibujaRectangulo(int x, int y, int ancho, int alto), en el que los argumentos x e y tienen un significado anlogo al que tienen en el mtodo CDC::TextOut. d) (2 puntos) Se pide un diagrama de clases que englobe en la mayor proporcin posible los programas pedidos en los apartados anteriores.
Apartado 1.a) t empl at e <cl ass I > cl ass Cont enedor { publ i c: i nt ancho; i nt al t o; / / Hast a l a l t i ma hi l er a compl et a vect or <Hi l er a<I > *> hi l er as; Cont enedor ( i nt ancho) ; voi d anyadi r ( I *) ; };
t empl at e <cl ass I > cl ass Hi l er a { publ i c: Cont enedor <I > * cont ; i nt pos; / / Al t ur a dent r o del cont enedor i nt l ar go; i nt al t o; vect or <I *> i t ems; Hi l er a( Cont enedor <I > *cont , i nt pos, I *i t em) ; Bool anyadi r ( I *i t em) ; };
/ / Par a ut i l i zar en l as cl ases Cont enedor e Hi l er a t empl at e <cl ass C> cl ass I t em{ publ i c: i nt ancho; i nt al t o; i nt posx; i nt posy; C cont eni do; };
t empl at e <cl ass I > voi d Cont enedor <I >: : anyadi r ( I *i t em) { i f ( hi l er as. si ze( ) == 0) { hi l er as. push_back( new Hi l er a<I >( t hi s, 0, i t em) ) ; r et ur n; } el se i f ( hi l er as[ hi l er as. si ze( ) - 1] - >anyadi r ( i t em) ) r et ur n; el se { al t o += hi l er as[ hi l er as. si ze( ) - 1] - >al t o; hi l er as. push_back( new Hi l er a<I >( t hi s, al t o, i t em) ) ; }; };
t empl at e <cl ass I > bool Hi l er a<I >: : anyadi r ( I *i t em) { i f ( l ar go + i t em- >ancho > cont - >ancho) r et ur n f al se; i t em- >posx = l ar go; i t em- >posy = cont - >al t o; i t ems. push_back( i t em) ; al t o = max( al t o, i t em- >al t o) ; l ar go += i t em- >ancho; r et ur n t r ue; };
Apartado 1.b) La versin que se muestra utiliza documentos y vistas; se puede hacer anlogamente sin utilizar documentos, utilizando directamente una ventana marco sin vista, con una vista de formulario o con un dilogo.
Mediante el wizard de Visual C++o por otro mtodo se definen de manera estndar las clases CCont enedor MFCApp, CCont enedor MFCVi ew y CCont enedor MFCDoc.
A la clase CCont enedor MFCDoc se le aade un atributo vect or <CSt r i ng *> cont eni do.
Se define una clase especfica de tems:
cl ass Cont enedor MFCI t em: I t em<CSt r i ng *> { Cont enedor MFCI t em( CSt r i ng *st r , CDC *cdc) ; };
El constructor de esta clase asigna las dimensiones al item utilizando el resultado del mtodo CDC: : Get Text Ext ent ( CSt r i ng) :
Cont enedor MFCI t em( CSt r i ng *st r , CDC *dc) : I t em<CSt r i ng *>( st r ) { CSi ze si ze = dc- >Get Text Ext ent ( *st r ) ; ancho = si ze. cx; al t o = si ze. cy; };
La clase CCont enedor MFCVi ew se hace que sea subclase de Cont enedor <Cont enedor MFCI t em> adems de serlo de CVi ew.
El mtodo CCont enedor MFCVi ew: : OnI ni t i al Updat e( ) asigna el ancho del contenedor y construye iterativamente un Cont enedor MFCI t empor cada cadena del contenido del documento, que aade al contenedor:
voi d CCont MFCVi ew: : OnI ni t i al Updat e( ) { CVi ew: : OnI ni t i al Updat e( ) ; Get Document ( ) - >cVi ew = t hi s; LPRECT r ect = new t agRECT; Get Cl i ent Rect ( r ect ) ; ancho = r ect - >r i ght ; f or ( i nt i = 0; i < Get Document ( ) - >cont eni do. si ze( ) ; i ++) anyade( CCont enedor MFI t em( Get Document ( ) - >st r i ngs[ i ] ) ) ; };
El mtodo de dibujado recorre las hileras y sus tems y dibuja en las posiciones correspondientes sus contenidos:
voi d CCont enedor MFCVi ew: : OnDr aw( CDC* pDC) { vect or <Hi l er a<I t em<St r i ng> > > hi l er as = get Document ( ) - >get Cont ai ner ( ) - >get Hi l er as( ) ; f or ( i nt i = 0; i < hi l er as. si ze( ) ; i ++) f or ( i nt j = 0; j < hi l er as[ i ] - >i t ems. si ze( ) ; j ++) pDC- >Text Out ( hi l er as[ i ] - >i t ems[ j ] - >posx, hi l er as[ i ] - >i t ems[ j ] - >posy, *hi l er as[ i ] - >i t ems[ j ] - >st r ) ; }; Apartado 1.c) Los cambios a realizar con respecto al apartado anterior son:
i) Definimos la clase I t emCont eni do y las subclases I t emCSt r i ng y I t emRect angul o:
cl ass I t emCont eni do { };
cl ass I t emCSt r i ng : publ i c I t emCont eni do { CSt r i ng st r ; };
cl ass I t emRect angul o : publ i c I t emCont eni do { i nt ancho; i nt al t o; };
El contenido del documento es un vector de punteros a I t emCont eni dos en lugar de CSt r i ngs.
ii) Se crean dos subclases de la clase Cont enedor MFCI t em: Cont enedor MFCI t emSt r i ng y Cont enedor MFCI t emRect , que son subclases respectivamente de I t em<I t emCSt r i ng> y de I t em<I t emRect angul o>. Los constructores calculan las dimensiones de los tems de distintas formas segn el caso (en un caso lo hacen como en el apartado anterior, en otro a travs del rectngulo). Adems, la clase Cont enedor MFCI t emtiene un mtodo virtual abstracto dr aw( CDC *) . Este mtodo se define en cada subclase mediante los mtodos CDC: : Text Out y CDC: : Di buj aRect angul o
iii) El mtodo de dibujado sustituye la llamada a pDC->TextOut por una llamada al mtodo draw sobre los tems, con pDC como argumento:
voi d CCont enedor MFCVi ew: : OnDr aw( CDC* pDC) { f or ( i nt i = 0; i < hi l er as. si ze( ) ; i ++) f or ( i nt j = 0; j < hi l er as[ i ] - >i t ems. si ze( ) ; j ++) hi l er as[ i ] - >i t ems[ j ] - >dr aw( pDC) ; };
Apartado 1.d)
Diagrama de clases para el apartado a):
Diagrama de clases para el apartado b) (no se incluye la clase de la aplicacin ni la cardinalidad de las relaciones):
Contenedor Hilera Item 1 1
El diagrama de clases para el apartado 1.c) es anlogo, excepto que la clase CString se sustituye por la jerarqua formada por la clase I t emCont eni do y las subclases I t emCSt r i ng y I t emRect angul o y anlogamente a la clase MFCItem se le aaden sus dos subclases:
Contenedor Hilera Item MFCItem ContMFCView CView ItemCont ContMFCDoc CDocument ItemCStr ItemRect ContMFCIStr ContMFCIRect Contenedor Hilera Item MFCItem ContMFCView CView CString ContMFCDoc CDocument CDocument Problema 2) (10 puntos) Completar el siguiente programa para que la salida sea la que se indica:
Programa: #i ncl ude <i ost r eam> #i ncl ude <st r i ng> usi ng namespace st d; cl ass X { publ i c: voi d f ( ) { cout << " Met odo f en cl ase X" << endl ; } }; cl ass Y { publ i c: voi d f ( ) { cout << " Met odo f en cl ase Y" << endl ; } }; voi d mai n( i nt ar gc, char * ar gv[ ] ) { X x; Y y; x. f ( ) ; y. f ( ) ; Z<X*> z1=&x; Z<Y*> z2=&y; z1. f ( ) ; z2. f ( ) ; } Salida: Met odo f en cl ase X Met odo f en cl ase Y Met odo f en cl ase X Met odo f en cl ase Y
Solucin:
t empl at e <cl ass T> cl ass Z { publ i c: T t ; Z ( T t ) : t ( t ) {} voi d f ( ) { t - >f ( ) ; } };
Problema 3) (10 puntos) Escribir el cdigo de la clase A para que la salida sea la que se indica, y que se verifique para cualesquiera valores de (x1,x2,x3):
Programa: #i ncl ude <i ost r eam> #i ncl ude <st r i ng> usi ng namespace st d; voi d mai n( i nt ar gc, char * ar gv[ ] ) { i nt x1=5, x2=7, x3=8; A a1( x1) , a2( x2) , a3( x3) ; a1. val or ( ) ; a2. val or ( ) ; a3. val or ( ) ; ( a1+=a2) +=a3; a1. val or ( ) ; a2. val or ( ) ; a3. val or ( ) ; ( x1+=x2) +=x3; cout << " Val or es: " << x1 << " , " << x2 << " , " << x3 << endl ; } Salida: Val or : 5 Val or : 7 Val or : 8 Val or : 20 Val or : 7 Val or : 8 Val or es: 20, 7, 8
Solucin:
cl ass A { publ i c: i nt x; A ( i nt x) : x( x) {} voi d val or ( ) { cout << " Val or : " << x << endl ; } A& oper at or += ( const A& a) { x=x+a. x; r et ur n *t hi s; }; };
Problema 4) Suponer un sistema de realizacin de preguntas basadas en mens, en el cual se formulan preguntas a un usuario y ste debe averiguar la respuesta correcta. Por ejemplo, un men basado en nmeros para dos iteraciones sera del estilo siguiente (ejemplo 1):
Pr egunt a: Capi t al de Fr anci a 1. Londr es 2. Roma 3. Par i s 4. Car acas I nt r oduce el numer o cor r ect o 1 Respuest a i ncor r ect a Pr egunt a: Capi t al de Fr anci a 1. Londr es 2. Roma 3. Par i s 4. Car acas I nt r oduce el numer o cor r ect o 3 Respuest a cor r ect a
Cada men corresponde a un estilo distinto. Por ejemplo, otro caso sera el estilo correspondiente a los mens basados en subcadenas, en donde el usuario debe responder con las dos primeras letras de la opcin ante las mismas preguntas formuladas con este otro tipo de men. En este caso el ejemplo (ejemplo 2) sera:
Pr egunt a: Capi t al de Fr anci a - Londr es - Roma - Par i s - Car acas I nt r oduce l as dos pr i mer as l et r as de l a sol uci on Pa Respuest a cor r ect a Pr egunt a: Capi t al de Fr anci a - Londr es - Roma - Par i s - Car acas I nt r oduce l as dos pr i mer as l et r as de l a sol uci on Ca Respuest a i ncor r ect a
a) Implementar este sistema en C++ usando el patrn de Fbrica Abstracta correspondiente al siguiente pseudocdigo para el mtodo main en el caso de un men de nmeros, de modo que la ejecucin de este mtodo main sea el ejemplo 1 anterior
i nt mai n( i nt ar gc, char * ar gv[ ] ) { <Cr eaci n de una f br i ca de mens de nmer os> <Cr eaci n por l a f br i ca de un men > <Cr ear l a pr egunt a " Capi t al de Fr anci a" par a el men> <Cr ear l a opci n " Londr es" par a el men> <Cr ear l a opci n " Roma" par a el men> <Cr ear l a opci n " Par s" par a el men, como l a cor r ect a> <Cr ear l a opci n " Car acas" par a el men> <r epet i r dos veces> <Ej ecut ar l a acci n pr egunt ar en el men> <Ej ecut ar l a acci n r esponder en el men> <f i n de r epet i ci n> }
En la implementacin se debern utilizar las plantillas vector y string (para representar colecciones de objetos y caracteres, respectivamente, sin utilizar arrays en ningn caso), liberando la memoria dinmica utilizada. Adems se debe cumplir (que es lo que permite este patrn de diseo) que para obtener el ejemplo 2 en lugar del ejemplo 1 baste con cambiar la lnea de <Cr eaci n de una f br i ca de mens de nmer os> por la correspondiente de cadenas <Cr eaci n de una f br i ca de mens de subcadenas>.
Solucin:
#i ncl ude <i ost r eam> #i ncl ude <vect or > #i ncl ude <st r i ng> usi ng namespace st d; cl ass Menu { pr ot ect ed: vect or <st r i ng> el ement os; st r i ng sol uci on; st r i ng pr egunt a; st r i ng r espuest a; publ i c: voi d cr ear Pr egunt a( st r i ng s) { pr egunt a=s; } voi d cr ear NuevaOpci on( st r i ng s, i nt cor r ect a=0) { el ement os. push_back( s) ; i f ( cor r ect a! =0) sol uci on=s; } voi d r esponder ( ) { i f ( r espuest a==sol uci on) cout << " Respuest a cor r ect a" << endl ; el se cout << " Respuest a i ncor r ect a" << endl ; } vi r t ual voi d pr egunt ar ( ) = 0; }; cl ass MenuDeNumer os : publ i c Menu { publ i c: vi r t ual voi d pr egunt ar ( ) { cout << " Pr egunt a: " << pr egunt a << endl ; f or ( i nt i =0; i <el ement os. si ze( ) ; i ++) { cout << ( i +1) << " . " << el ement os[ i ] << endl ; } cout << " I nt r oduce el numer o cor r ect o" << endl ; i nt j ; ci n >> j ; r espuest a=el ement os[ j - 1] ; } }; cl ass MenuDeSubcadenas : publ i c Menu{ publ i c: vi r t ual voi d pr egunt ar ( ) { cout << " Pr egunt a: " << pr egunt a << endl ; f or ( i nt i =0; i <el ement os. si ze( ) ; i ++) { cout << " - " << el ement os[ i ] << endl ; } cout << " I nt r oduce l as dos pr i mer as l et r as de l a sol uci on" << endl ; st r i ng s; ci n >> s; f or ( i nt j =0; j <el ement os. si ze( ) ; j ++) { i f ( el ement os[ j ] . subst r ( 0, 2) ==s) r espuest a=el ement os[ j ] ; } } }; cl ass Fabr i caDeMenus { publ i c: vi r t ual Menu* cr ear Menu ( ) = 0; }; cl ass Fabr i caDeMenusDeNumer os : publ i c Fabr i caDeMenus { publ i c: vi r t ual Menu* cr ear Menu ( ) { r et ur n new MenuDeNumer os( ) ; } }; cl ass Fabr i caDeMenusDeSubcadenas : publ i c Fabr i caDeMenus { publ i c: vi r t ual Menu* cr ear Menu ( ) { r et ur n new MenuDeSubcadenas( ) ; } }; i nt mai n( i nt ar gc, char * ar gv[ ] ) { Fabr i caDeMenus* f ; / / f =new Fabr i caDeMenusDeNumer os ( ) ; f =new Fabr i caDeMenusDeSubcadenas ( ) ; Menu* m=f - >cr ear Menu( ) ; m- >cr ear Pr egunt a( " Capi t al de Fr anci a" ) ; m- >cr ear NuevaOpci on( " Londr es" ) ; m- >cr ear NuevaOpci on( " Roma" ) ; m- >cr ear NuevaOpci on( " Par i s" , 1) ; m- >cr ear NuevaOpci on( " Car acas" ) ; f or ( i nt i =0; i <2; i ++) { m- >pr egunt ar ( ) ; m- >r esponder ( ) ; } del et e m; del et e f ; r et ur n 0; }
b) Dibujar el diagrama de clases necesarias para los ejemplo 1 y ejemplo 2.
Solucin:
MenuDeNumeros +preguntar(): void Menu #elementos: vector<string> #solucion: string #pregunta: string #respuesta +crearPregunta(s:string): void +crearNuevaOpcion(string,correcta:int): void +responder(): void +preguntar() FabricaDeMenus +crearMenu(): Menu FabricaDeMenusDeSubcadenas +crearMenu(): Menu MenuDeSubcadenas +preguntar(): void FabricaDeMenusDeNumeros +crearMenu(): Menu
c) Dibujar el diagrama de secuencia correspondiente al ejemplo 1
una FabricaDeMenusDe Numeros un MenuDeNumeros un Usuario crearMenu new crearPregunta * crearNuevaOpcion preguntar responder new