Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

2.poo

300 views

Published on

  • Be the first to comment

  • Be the first to like this

2.poo

  1. 1. Programaci´n Modular. ETSIT. 1o C. o Apuntes del profesor Juan Falgueras. Curso 2001/02 versi´n: 28 de abril de 2003 o5Programaci´n orientada a objetos oContenido5. Programaci´n orientada a objetos o 1 5.1. Introducci´n a C++ . . . . . . . . o . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 5.2. Diferencias entre C y C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 5.3. Clases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 5.4. Definici´n de clases . . . . . . . . o . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 5.5. M´todos . . . . . . . . . . . . . . e . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 5.6. Constructores y Destructores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 5.7. Sobrecarga . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 5.8. Entrada y salida en C++ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115. Programaci´n orientada a objetos o5.1. Introducci´n a C++ o El lenguaje C++ fue desarrollado por Bjarne Stroustrup1 de AT&T Bell Laboratories durantelos 80. El autor expandi´ enormemente el lenguaje C para dar soporte a principios de dise˜o m´s o n amodernos. La diferencia m´s importante entre C y C++ est´ en el soporte para clases, pero son a afundamentales tambi´n: e 1. Sobrecarga de operadores, que hace posible dar significados a˜adidos a los operadores tradi- n cionales. 2. Plantillas (templates), que permiten escribir pre-c´digo muy reutilizable sin concretar a´n o u elementos variables. 3. Gesti´n de excepciones, uniformando dando soporte a la detecci´n y respuesta a los errores o o de ejecuci´n. oSin embargo uno de los objetivos que se propuso el autor fue el de mantener a´n compatibilidad con uel lenguaje germinal C en lo posible. As´ todas las posibilidades del est´ndard C est´n igualmente ı a apresentes en C++. Esto, sin embargo no significa que todos los programas escritos en C compilenen C++; existen restricciones en C++ respecto a C sobre todo en aras de una mayor seguridad.5.2. Diferencias entre C y C++ Adem´s de las grandes novedades relativas a la programaci´n orientada a objetos (clases, a osobrecarga, derivaci´n, funciones virtuales, plantillas y gesti´n de excepciones), C++ a˜ade a C o o npeque˜as diferencias que conviene conocer. n 1 http://www.research.att.com/~bs/homepage.html
  2. 2. 5.2 Diferencias entre C y C++ 2Comentarios C++ tiene comentarios de ´mbito limitado a una s´la l´ a o ınea, frente a C que no acabael comentario al terminar la l´ ınea. Como ya habremos visto, los comentarios de C++ empiezan con// y terminan con el final de la l´ ınea. Esto no quiere decir, por otra parte, que no se puedanutilizar tambi´n la t´cnica de comentarios de C. e eEtiquetas frente a nombres de tipo Los identificadores de estructuras, uniones y enumeradosbastan para definir en C++ el propio tipo sin necesidad de crear un tipo con typedef. As´ en vez ıde typedef struct {int numerador, denominador;} Fracc;basta (en C++) escribir: struct Fracc {int numerador, denominador;};pudi´ndose desde entonces definir estructuras de tipo Fracc;. eFunciones sin argumentos No hay necesidad de usar la palabra void cuando se definen fun-ciones sin argumentos: int leeInt(void); // en C int leeInt(); // es suficiente en C++Argumentos con valor por defecto C++ permite que un argumento tome un valor por defectocuando no se especifique un valor real en la llamada. Por ejemplo: void wrLn(int n = 1) { // tiene un par´metro que toma por defecto el valor 1 a while (n-- > 0) putchar(’n’); }puede ser llamado con o sin par´metros a wrLn(3); // escribir´a tres saltos de l´nea ı ı wrLn(); // escribir´a uno ıSi se define la funci´n int a(int a=1, int b=2, int c), ¿qu´ significa a(4,5)? Podr´ significar o e ıavarias cosas con lo que los argumentos con valores por defecto siempre deben estar juntos al finalde la lista de argumentos formales. int a(int c, int a=1, int b=2) hace que a(1), ´ a(1,2) o´ a(1,2,3) sean todos no-ambiguos.2oFunciones inline El lenguaje C explot´ enormemente el uso del preprocesado l´xico. El prepro- o ecesador act´a antes que el compilador substituyendo sint´cticamente los elementos #define’dos u apor su equivalente, sin que el preprocesador interprete el significado sino s´lo los tokens l´xicos que o eintervienen. Esta idea proven´ de los antiguos lenguajes ensambladores de los que C era cercano ıaheredero. La #define’ci´n de s´ o ımbolos es s´lo el mecanismo m´s simple; cpp, el preprocesador, o aprevio a C, permite la expansi´n de macros. Una macro es un s´ o ımbolo con argumentos. Entoncesse sustituye el s´ ımbolo por la expresi´n y los argumentos se intercalan en la expresi´n all´ d´nde o o ı ose indique. La potencia sint´ctica del preprocesado de macros de C tiene sin embargo algunos puntos aoscuros. Imagin´monos un macro e #define cuadrado(x) (x*x) 2 En otros lenguajes es posible poner nombres a los argumentos en la propia llamada, a(1, c=>3) permitir´ que ıab tomase libremente su valor por defecto. Esto ayuda a manejar funciones con muchos argumentos superfluos.
  3. 3. 5.2 Diferencias entre C y C++ 3que significa que all´ en el fuente en C d´nde aparezca cuadrado(algo) lo debe substituir por ı ocuadrado(algo*algo). Insistimos, el preprocesador no entra en interpretar lo que signifique nin-guna de las expresiones anteriores, eso se lo deja al compilador que recoje el resultado del prepro-cesado. Ve´mosla en acci´n en diversas ocasiones como: a o void f(double d, int i) { r = cuadrado(d); // bien r = cuadrado(i++); // mal: significa (i++*i++) r = cuadrado(d+1); // mal: significa (d+1*d+1); que es, (d+d+1) // ... }El problema de “d+1” se resuelve mediante el a˜adido de par´ntesis en el macro: n e #define cuadrado(x) ((x)*(x)) /* mejor */pero el de “i++” no tiene soluci´n en C. C++ a˜ade un tipo de “funciones” que se expanden o n(sint´cticamente) en el momento de ser utilizadas. As´ no es un preprocesador, el preprocesador de a ıC, que no tiene en cuenta la sem´ntica de las operaciones C, el que se encarga de expandir estas aconstrucciones sint´cticas sino el propio compilador en C++ el que expande de manera correcta aestos macros, teniendo sobre todo en cuenta la manipulaci´n correcta de los argumentos. o inline int icuadrado(int x) {return x * x;}El hecho de que sea el propio compilador el que expanda el cuerpo de la funci´n obliga, sin embargo, oa que el tipo del argumento sea conocido, algo que C++ no puede resolver excepto con el uso deplantillas, que son, sin embargo, inadecuadas para este prop´sito. oPaso de par´metros por referencia En C todos los par´metros siempre son pasados por a avalor, esto es, copiando el par´metro que se ponga en la llamada, par´metro actual, a la variable a areceptora en el par´metro formal ya como variable local del procedimiento. Esto nos obliga a autilizar a poner las direcciones de las variables (& en los par´metros de la llamada y a apuntar amediante esas direcciones (*) dentro del procedimiento para poder modificar los valores de lasvariables pasadas. void intercambia(int *a, int *b) { int temp= *a; *a = *b; *b = temp; }y es llamado mediante intercambia(&i, &j);. O la tan famosa scanf que require referencias alos elementos a leer. Por ejemplo: for (i=0; i<N; i++) scanf("%d", &a[i]); Esta t´cnica es inc´moda e insegura3 . C++ detalla y permite un mayor control del paso de e opar´metros a˜adiendo la posibilidad del paso de par´metros por referencia. En este caso, el par´me- a n a atro actual no necesita llevar el indicador de que se va modificar (&) sino que es en el par´metro a 3 Aunque esta t´cnica es inc´moda, tambi´n hay que decir que es m´s expl´ e o e a ıcita en cuanto a la peligrosidad deuso de este tipo de modificaciones no locales. Es m´s expl´ a ıcita porque manifiesta el cambio mediante el signo *en el procedimiento. Sin embargo respecto a los arrays el tema es m´s oscuro y el cambio se produce siempre ya aque el propio nombre del array es la direcci´n del bloque de datos del mismo. Recordemos que en C los par´ntesis o ecuadrados [] act´ an como operadores de indirecci´n siempre: x[i] equivale *(x+i) u o
  4. 4. 5.2 Diferencias entre C y C++ 4formal de la declaraci´n del procedimiento donde se indica que se va a recibir al par´metro por o areferencia. Esto es mucho m´s c´mo en muchos casos y es preferido por la mayor´ de los pro- a o ıagramadores. Es un mecanismo a˜adido. El compilador se encarga de los aspectos ‘sucios’ de la nmodificaci´n del par´metro actual. No hay que usar & cada vez que se llame en el par´metro o a aformal ni * en la funci´n cada vez que se quiera acceder al valor del par´metro. En el caso del o aprocedimiento de intercambio anterior escribiremos: void intercambia(int& a, int& b) { int temp= a; a = b; b = temp; }y es llamado mediante intercambia(i, j);. N´tese que aparece una nueva notaci´n: se declara o oun par´metro que es una referencia a un tipo de elemento. C carece de las posibilidades de la areferencia y por ello usa los punteros siempre.Operadores new y delete En vez de las funciones malloc, calloc, realloc y free, aunqueC++ las puede utilizar, C++ introduce un operador (y por lo tanto una sintaxis diferente) paraadquirir nuevos bloques de memoria y/o crear nuevos objetos en ella. Por ejemplo: int *pint, *pin2, *aint; pint = new int; // adquiere memoria adecuada para un entero pin2 = new int(33); // .. e inicializa su contenido a 33 aint = new int[10]; // ´dem para un array de 10 enteros ıComo es de esperar, new devolver´ un puntero nulo (0 ´ NULL) cuando no pueda encontrar un a oespacio suficiente de memoria. El tama˜o del espacio lo calcula el propio compilador seg´n el n uobjeto a ubicar. En esto est´ la mayor diferencia con C. Por otro lado a delete pint; // libera la memoria conseguida delete[] aint; // requiere [] con arraysEl hecho de que sea un operador hace m´s c´modo su uso ya que tampoco hace falta el incluir a o<stdlib.h> con el prototipo (interfaz) de malloc, etc. sino que el propio compilador expande eloperador al estilo de un macro: pa = new int; // (int *) malloc(sizeof(int))es equivalente al macro: #define new(X) (X *) malloc(sizeof(X))encarg´ndose el compilador de C++ de estos detalles. aConversi´n de tipos El operador de conversi´n de tipos de C se ve ampliado en C++ y adem´s o o ase usa con una sintaxis un poco diferente a´n en el caso sencillo de adaptaci´n de tipos sencilla u ocom´n: u int num = 33; char c1 = (char) num; // estilo C char c2 = char (num); // estilo C++pero existen en C++ otros conversores de tipo como son conversi´n de atributo const, reinterpretar oel significado de los bytes (sin cambio de valores) y conversores entre clases, de una sem´ntica m´s a acompleja de la que se pretende cubrir en esta introducci´n. o
  5. 5. 5.3 Clases 55.3. Clases La mayor diferencia entre C y C++ est´ en soporte que el ultimo ofrece para las clases 4 . a ´Esencialmente una clase es un tipo abstracto de datos: colecci´n de datos junto a operadores para oacceder y modificarlos. Con las clases podremos, pues construir nuevos tipos de datos, que siendocuidadosos en su construcci´n, ser´n equivalentes en su trato, con los tipos predefinidos por el o alenguaje. As´ podr´ ı ıamos definir una clase Complejo y variables Complejo c1, c2, c3;y, mediante la sobrecarga de operadores que C++ permite, operar correctamente con nuestrospropios operadores de multiplicaci´n, etc´tera o e c3 = c1 * c2;adem´s del resto de operaciones que queramos definir sobrecargando los operadores propios del alenguaje. Pero el uso de las clases es a´n m´s interesante desde el punto de vista de la programaci´n u a oorientada a objetos. Si estamos desarrollando una interfaz de usuario, prob´blemente tengamos aun objeto panel que puede siembre abrirse, cerrarse, ocultarse, etc. Pero despu´s veremos que eun di´logo es un panel m´s otra serie de operaciones como la de interactuar con el teclado. Una a aventana ser´ otro tipo de panel que tendr´ barra de desplazamiento, etc. Luego ser´n todos objetos a a aderivados del primero con comportamientos heredados de aqu´l m´s particularidades propias. Si e alo que estamos desarrollando es una aplicaci´n de contabilidad, podremos tener una clase Cuenta ocon operaciones comunes como deposito, retiro, etc. Las clases facilitan la programaci´n de aplicaciones complejas haciendolas m´s legibles y con- o atrolables. Sin embargo el precio es una mayor dificultad de aprendizaje del lenguaje. La progra-maci´n orientada a objetos es adecuada en aplicaciones medianas a grandes, no tanto en peque˜as o naplicaciones.5.4. Definici´n de clases o Definir una clase en C++ es muy parecido a definir una structura en C. En su forma m´s asimple, la el aspecto de una clase es id´ntico al de una estructura, usando la palabra class en vez ede struct: class Complejo { float parteReal; float parteImaginaria; };dici´ndose que parteReal y parteImaginaria son miembros de la clase Complejo. La convenci´n e ode comenzar los nombres de los tipos con may´sculas es adecuada tambi´n aqu´ pero por supuesto u e ı,depende de las normas de estilo del grupo de programadores, no del lenguaje. En una terminolog´ m´s general en programaci´n orientada a objetos, los datos miembros ıa a oson los atributos de la clase. Una vez definida la clase, su nombre se puede usar para declarar variables como se hac´ con ıalas estructuras: Complejo c1, c2;N´tese que el identificador (la etiqueta) sirve en C++ como nombre del tipo y no es necesario oescribir class Complejo c1;. A las variables c1 y c2 se les llama instancias de la clase Complejo. Una instancia decualquier clase se denomina objeto. Los miembros de una estructura son accedidos mediante los operadores . y ->. En una clase,por otro lado, los miembros est´n ocultos, mientras no se indique lo contrario, o sea, que por adefecto son inaccesibles, de manera que las siguientes acciones son ilegales: 4 El nombre original de C++ era C with Classes: C + C.
  6. 6. 5.5 M´todos e 6 c1.parteReal = 0.0; // ilegal, no accesible im = c2.parteImaginaria; // ilegal, no accesibleDecimos que parteReal y parteImaginaria son miembros privados de la clase Complejo. Pero si as´ lo queremos, podemos hacer accesibles los miembros de una clase declar´ndolos ı apublic: class Complejo { public: float parteReal; float parteImaginaria; };Podemos mezclar partes p´blicas y privadas de una clase: u class Complejo { public: float parteReal; private: float parteImaginaria; };N´tese el uso de private para comenzar una secci´n de declaraciones ocultas. Al principio de la o odeclaraci´n si no se indica otra cosa se supone impl´ o ıcitamente la palabra private, por lo que loanterior es equivalente a: class Complejo { float parteImaginaria; public: float parteReal; };5.5. M´todos e Si no son visibles los miembros privados de una clase, ¿c´mo se pueden modificar o ver sus ovalores? La respuesta es ingenua: las funciones que necesiten acceder a los datos miembros de unaclase deben estar declarados dentro de la misma clase. Son las funciones miembro o m´todos. e Esta es la t´cnica que C++ utiliza para ver/modificar sus datos miembro. La diferencia entre elas clases y las estructuras empieza realmente aqu´ para controlar el uso de la informaci´n que ı, odetermina el estado de un objeto se deben usar m´todos que son las funciones, v´ de acceso e ıas,seguras para controlar y presentar la informaci´n oculta de manera adecuada. As´ un objeto tiene o ıun estado interno reconocible por su comportamiento ante las llamadas a sus m´todos. e As´ı: class Complejo { public: void crear(int preal int pimag); void print(); private: float parteReal; float parteImaginaria; };tienen los m´todos crear y print que son miembros p´blicos, accesibles desde fuera de la clase. e uPara acceder a los m´todos de los objetos se utiliza como para acceder sus datos miembro, la enotaci´n “punto”: o c1.crear(0.0, 1.0); // c1 contiene el n´mero complejo 0 + 1 i u c1.print(); // imprimir´a 0 + 1 i ı
  7. 7. 5.5 M´todos e 7Respecto al estilo empleado en C, estas llamadas son extra˜as ya que se conoce al objeto al que nse llama, no poni´ndolo como par´metro, sino anteponi´ndolos como prefijo. e a e No todos los m´todos de una clase tienen que ser p´blicos. Por ejemplo: e u class Fraccion { public: void crear(int num, int denom); void print(); private: void reduce(); int numerador, denominador;La filosof´ subyacente es la de ofertar (hacer p´blico) s´lo lo necesario e imprescindible para, ıa u opor un lado no confundir innecesariamente al usuario del objeto y, por otro, evitar errores en lamanipulaci´n de los mismos. o Hasta ahora s´lo hemos definido los m´todos de las clases y objetos de aqu´llas, pero ¿d´nde o e e oest´n los algoritmos que realizan tales m´todos? a e Una posibilidad es definir cada m´todo m´s adelante, fuera de la definici´n de la clase. Por e a oejemplo, en el caso de la funci´n crear de las fracciones: o void Fraccion.crear(int num, int denom) { numerador = num; denominador = denom; reduce(); }N´tese c´mo Fraccion:: precede el nombre de la funci´n. Esta es la notaci´n que C++ emplea o o o opara distinguir funciones ordinarias de los m´todos propios de una clase. Observar que crear tiene eacceso directo a los datos miembros de la clase propia. En general esto es as´ ya sean los datos ıp´blicos o privados. u En vez de definir posteriormente los m´todos de una clase, se pueden resolver inline sobre la emarcha en la propia definici´n de la clase: o class Fraccion { public: void crear(int num, int denom) {numerador = num; denominador = denom; reduce();}; void print(); private: void reduce(); int numerador, denominador;esto es conveniente, s´lo si el cuerpo del m´todo es corto. o e A˜adamos el m´todo mul para multiplicar modificando ´sta por otra fracci´n: n e e o class Fraccion { public: void crear(int num, int denom); void print(); Fraccion mul(Fraccion f); // m´todo para multiplicar e private: void reduce(); int numerador, denominador; Despu´s tendr´ e ıamos que escribir la definici´n (antes escribimos la declaraci´n) de la funci´n o o omul:
  8. 8. 5.6 Constructores y Destructores 8 Fraccion Fraccion::mul(Fraccion f) { Fraccion res; res.numerador = numerador * f.numerador; res.denominador = denominador * f.denominador; res.reduce(); return res; } Inicialmente la funci´n mul puede parecer algo misteriosa: est´ claro cu´l es uno de los mun- o a atiplicandos, el argumento f, pero ¿d´nde est´ el otro? La respuesta est´ en la forma en la que mul o a aes llamado: f3 = f1.mul(f2);5.6. Constructores y Destructores Para asegurar que las instancias de una clase se inicializan adecuadamente la clase puede tenerunos funciones especiales denominadas constructores. As´ ımismo la clase puede tener destruc-tores, funciones que arreglan y dejan las cosas como estaban antes de eliminarse el objeto. Lointeresante en principio respecto a los constructores y destructores es que son llamados autom´ti-acamente sin una llamada expl´ ıcita. Hay que tener cuidado con esto. Nosotros en nuestro ejemplo, hasta ahora, hemos usado una llamada expl´ ıcita crear paraasignar valores a los atributos. Dada la importancia de la inicializaci´n y la limpieza posterior C++ osoporta el uso de funciones contructores y destructores autom´ticamente llamados en el momento ade la creaci´n de una nueva instancia de la misma y en el momento de su destrucci´n, en el o omomento en que la instancia deja de existir, generalmente esto ultimo ocurrir´ cuando la funci´n ´ a oen la que est´ el objeto local deje de existir. a La sintaxis elegida en C++ es de que toda funci´n con el mismo nombre de la clase que ono devuelve nada (ni void siquiera) es un constructor. Mientras que toda funci´n con el mismo onombre de la clase antecedido de una tilde ~ es un destructor. En nuestro ejemplo: class Fraccion { public: Fraccion(int num, int denom) {numerador = num; denominador = denom; reduce(); } ... };Notemos que el constructor va en la parte p´blica de la clase. Los constructores pueden ser llama- udos expl´ıcitamente como los otros m´todos pero lo m´s interesante de ellos es que son llamados e aimpl´ ıcitamente en el momento de crear una nueva instancia del objeto: Fraccion f(7,3); // declara e inicializa f a 7/3 Pero ¿qu´ ocurrir´ con la declaraci´n? e ıa o Fraccion muchasFracs[3];El compilador se quejar´ inmediatamente de que no estamos poniendo los argumentos exigidos ıaen la llamada impl´ ıcita de construcci´n de cada instancia de fracci´n. o o Una primera soluci´n a esto (como veremos en §5.7) ser´ crear un constructor m´s sobrecar- o ıa agando el anterior pero sin par´metros. Como veremos esta es una soluci´n factible, pero la m´s a o aadecuada es la de usar par´metros por defecto: a
  9. 9. 5.6 Constructores y Destructores 9 class Fraccion { public: Fraccion(int num=0, int denom=1) {numerador = num; denominador = denom; reduce(); } ... };que, como sabemos permite mucha mayor flexibilidad en las llamadas. Podr´ ıamos crear: Fraccion f(7,3); // 7/3 Fraccion f(7); // 7/1 Fraccion f; // 0/1 Fraccion f[10]; // 10 fracciones f[0]..f[9] inicializadas a 0/1 Los constructores y destructores son especialmente importantes cuando los objetos necesitanadquirir din´micamente memoria del sistema para almacenar sus datos (atributos) mediante new ay delete. Veamos un ejemplo. La clase Cadena puede contener cadenas de caracteres de cualquier lon-gitud. La podemos definir: class Cadena { .. private: char *texto; int long; };O sea un puntero a la ristra de caracteres y, optimizando mucho su c´lculo, una variable que recoja asu longitud. La manera m´s adecuada de usar estos objetos ser´ inicializ´ndolos con un valor y posterior- a ıa amente modific´ndolos. Tendr´ a ıamos: class Cadena { public: Cadena(const char *s); // constructor private: char *texto; int long; }Y entonces: Cadena::Cadena(const char *s) { long = strlen(s); text = new char[long+1]; strcpy(text, s); }Despu´s de calcular la longitud de la cadena a la que apunta s el constructor llama al operador enew para conseguir espacio de memoria suficiente para copiar la cadena; finalmente el constructorcopia la cadena en el espacio reci´n conseguido. e Al construir objetos de tipo Cadena har´ ıamos: Cadena c1("Hola"), c2("y adi´s."); oPara que esta clase tenga alg´n inter´s habr´ l´gicamente que a˜adirle m´todos para modificar y u e ıa o n eleer la cadena. As´ ımismo podr´ ıamos tener un constructor con valor por defecto nulo:
  10. 10. 5.7 Sobrecarga 10 class Cadena { public: Cadena(const char *s = 0); // constructor ... }y despu´s: e Cadena::Cadena(const char *s) { if (s == 0) { long = 0; text = 0; } else { long = strlen(s); text = new char[long+1]; strcpy(text, s); } } La cuesti´n viene cuando este objeto deje de existir, ya sea porque era local a una funci´n o oo porque se acabe el programa, etc. Entonces habr´ que eliminar la memoria conseguida con ıanew mediante el delete adecuado. C++ aporta un destructor por defecto que si se dice nada lounico que hace es liberar la memoria que ocupaban los miembros de la instancia de la clase. Esto´es lo usual tambi´n con variables est´ticas. Sin embargo C++ es incapaz de invertir el algoritmo e ade construcci´n empleado para almacenar la cadena de caracteres en el objeto y as´ liberar la o ımemoria que usaba. En este caso es pues necesario a˜adir un desctructor expl´ n ıcito a la clase queser´ llamado autom´ticamente por C++ cuando el objeto desaparezca: a a class Cadena { public: Cadena(const char *s = 0); ~Cadena() { delete[] text; } // destructor ... }5.7. Sobrecarga En C++ dos o m´s funciones dentro del mismo ´mbito pueden compartir el mismo nombre. a aCuando las funciones est´n sobrecargadas es el compilador el que decide en base a la firma a(signature) de la funci´n cu´l es la que debe ser llamada. S´lo en caso de ambig¨edad el compi- o a o ulador no podr´ decidir. La firma est´ compuesta del nombre, argumentos, tipo y modo de uso de ıa alos argumentos y tipo y modo del posible valor devuelto. As´ podr´ ı ıamos tener: void intercambiar(int& a, int &b); void intercambiar(char& a, char &b); // sobrecargaday despu´s e intercambiar(a_int, b_int); // llamar´a a la primera ı intercambiar(letraa, letrab); // llamar´a a la segunda ı Las funciones miembro de una clase tambi´n pueden ser sobrecargadas (lo cual es el uso m´s e afrecuente de la sobrecarga). En el caso de Cadena es m´s f´cil utilizar la sobrecarga que considerar a aaparte el caso de no tener par´metros el constructor: a
  11. 11. 5.8 Entrada y salida en C++ 11 class Cadena { public: Cadena(const char *s = 0); Cadena() {text = 0; long =0; } // sobrecargada ... } Adem´s de admitir la sobrecarga de funciones, C++ admite la sobrecarga de operadores. De ahecho esto ya es habitual en el caso de los tipos simples predefinidos. Por ejemplo, podemos hacer3*2 llamando as´ al operador multiplicaci´n de enteros o 3.1*2.0 que llama a un operador distinto, ı oel multiplicador de n´meros reales. La sobrecarga de operadores es particularmente interesante upara redefinir los operadores usuales ampliando sus posibles argumentos con los nuevos objetos. Elresultado es un aspecto mucho m´s natural de las operaciones que reutilizan nombres u operadores aconocidos en vez de tener que recordar multitud de nombres nuevos para cada tipo u objeto nuevo. En el caso de Fraccion ser´ mucho m´s f´cil el uso de la multiplicaci´n reemplazando el ıa a a om´todo mul por el operador *. Hacer esto es tan f´cil como substituir el nombre mul por operator* e aen la declaraci´n y definici´n del m´todo: o o e class Fraccion { public: ... Fraccion operator*(Fraccion f); // m´todo para multiplicar e private: ...La implementaci´n de operator* es id´ntica que la de mul. o e Cuando un operador se define como m´todo de una clase uno de sus operandos est´ siempre e aimpl´ıcito. As´ el operador que acabamos de definir es un operador binario, no unario y cuando ı,escribimos sentencias como: f1 * f2;el compilador nota que f1 es un objeto Fraccion y mira en la clase Fraccion buscando un operadoroperator* para convertir la expresi´n en: o f1.operator*(f2);5.8. Entrada y salida en C++ Aunque los programas en C++ pueden utilizar perfectamente <stdio.h>, C++ dispone de unaalternativa a la cl´sica librer´ de entrada y salida. La cabecera m´s importante de la nueva librer´ a ıa a ıaes <iostream.h> que define varias clases, incluyendo istream (canal de entrada, teclado, etc.) yostream (canal de salida, pantalla, etc.). Los programas simples que toman su entrada del tecladoy presentan sus resultados en la pantalla usan el objeto cin para la entrada y el objeto cout parala salida. cin es una instancia de la clase istream y cout es una instancia de la clase ostream. Las clases istream y ostream tienen muchos operadores sobrecargados para permitir la saliday entrada de los tipos est´ndard. La clase istream sobrecarga >> mientras que la clase ostream asobrecarga a <<. De esta forma una sesi´n interactiva ser´ o ıa: cout << "Introducir un n´mero: "; u cin >> n; cout << "su cuadrado es: " << n*n << endl;Recordemos que estamos llamando a los operadores ostream::operator<< de la instancia coutde la clase ostream y al operador istream::operator>> de la instancia cin de la clase istream.Estos est´n fuertemente recargados, para argumentos de tipo cadena, n´mero, etc´tera. a u e Entre las ventajas de usar la librer´ iostream est´n: ıa a
  12. 12. 5.8 Entrada y salida en C++ 12 Podemos ampliar la entrada y salida us´ndo los mismos operadores para las clases que a definamos. Es m´s segura ya que no se producen nunca incoherencias entre el tipo de datos esperado en a el formato de printf o scanf con el de los par´metros pasados. Estas incoherencias llevan a f´cilmente, en el caso de scanf a graves fallos de funcionamiento. a Es m´s r´pida ya que la decisi´n de qu´ algoritmo de salida para el tipo hay que usar se toma a a o e en el momento de compilar y no hay que interpretar el formato en momento de la ejecuci´n. o Hay que decir tambi´n que printf y scanf son m´s flexibles y potentes. e a La jerarqu´ de clases de la que deriva <iostream> se esquematiza en la Figura 1: ıa ios_base ios istream ostream iostream ifstream ofstream istringstream ostringstream fstream stringstreamFigura 1: Jerarqu´ de la que derivan las clases para manipulaci´n de la entrada y salida est´ndares ıa o a<iostream> y de ficheros fstream. Juan Falgueras Dpto. Lenguajes y Ciencias de la Computaci´n o Universidad de M´laga a Despacho 3.2.32

×