Your SlideShare is downloading. ×
  • Like
Manual cpp
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

×

Now you can save presentations on your phone or tablet

Available for both IPhone and Android

Text the download link to your phone

Standard text messaging rates apply

Manual cpp

  • 659 views
Published

 

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
659
On SlideShare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
4
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Una breve introducci´n a C++ o V´ ıctor Mu˜oz nContenidos1 Introducci´n o 32 Estructura b´sica de un programa a en C++ 3 2.1 El programa m´s simple . . . . . a . . . . . . . . . . . . . . . . 3 2.2 Definici´n de funciones . . . . . . o . . . . . . . . . . . . . . . . 4 2.3 Nombres de variables . . . . . . . . . . . . . . . . . . . . . . . 4 2.4 Tipos de variables . . . . . . . . . . . . . . . . . . . . . . . . . 4 2.5 Ingreso de datos desde el teclado . . . . . . . . . . . . . . . . 6 2.6 Operadores aritm´ticos . . . . . . e . . . . . . . . . . . . . . . . 6 2.7 Operadores relacionales . . . . . . . . . . . . . . . . . . . . . . 7 2.8 Asignaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.9 Conversi´n de tipos . . . . . . . . o . . . . . . . . . . . . . . . . 83 Control de flujo 9 3.1 if, if... else, if... else if . . . . . . . . . . . . . . . 9 3.2 Expresi´n condicional . . o . . . . . . . . . . . . . . . . . . . . . 10 3.3 switch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 3.4 while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 3.5 for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 3.6 do... while . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 3.7 goto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124 Funciones 12 4.1 Funciones tipo void . . . . . . . . . . . . . . . . . . . . . . . 12 4.2 return . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 4.3 Funciones con par´metros a . . . . . . . . . . . . . . . . . . . . 13 4.4 Par´metros default . . . . a . . . . . . . . . . . . . . . . . . . . 15 1
  • 2. 4.5 Alcance, visibilidad, tiempo de vida . . . . . . . . . . . . . . . 16 4.6 Recursi´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 o5 Matrices 17 5.1 Declaraci´n e inicializaci´n . . . . . . . . o o . . . . . . . . . . . . 17 5.2 Matrices como par´metros de funciones . a . . . . . . . . . . . . 18 5.3 Matrices multidimensionales . . . . . . . . . . . . . . . . . . . 19 5.4 Matrices de caracteres: cadenas (strings) . . . . . . . . . . . . 19 5.4.1 string.h . . . . . . . . . . . . . . . . . . . . . . . . . . 20 5.4.2 Input/Output de cadenas . . . . . . . . . . . . . . . . 206 Clases 21 6.1 Definici´n . . . . . . . . . . . . . . . . o . . . . . . . . . . . . . 23 6.2 Miembros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 6.3 Miembros p´blicos y privados . . . . . u . . . . . . . . . . . . . 24 6.4 Operador de selecci´n (.) . . . . . . . . o . . . . . . . . . . . . . 25 6.5 Implementaci´n de funciones miembros o . . . . . . . . . . . . . 26 6.6 Constructor . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 6.7 Destructor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 6.8 Matrices de clases . . . . . . . . . . . . . . . . . . . . . . . . . 297 Sobrecarga 29 7.1 Sobrecarga de funciones . . . . . . . . . . . . . . . . . . . . . 29 7.2 Sobrecarga de operadores . . . . . . . . . . . . . . . . . . . . . 30 7.3 Coerci´n . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 o8 Punteros 319 Herencia 32 2
  • 3. 1 Introducci´n oEstos apuntes corresponden a un peque˜o intento de ordenar los temas nabordados en el curso de Computaci´n para Matem´ticos dictado el Primer o aSemestre de 1998. No pretendo que sean tomados muy en serio, en el sen-tido que est´n dise˜ados para satisfacer las m´ a n ınimas necesidades del curso,sirviendo como un ayuda-memoria de los t´picos abordados, para futura oreferencia. No se consideran todas las posibilidades del lenguaje, y las ex-plicaciones est´n reducidas al m´ a ınimo o est´n ausentes del todo, de modo aque creo son m´s utiles para quienes ya sepan algo de C++ (idealmente los a ´alumnos del curso una vez terminado ´ste) y quieran recordar alg´n detalle e ude sintaxis ya olvidado. Tambi´n pueden servir para personas con alguna eexperiencia en otros lenguajes de programaci´n y que deseen comenzar el oaprendizaje de C++. El mundo est´ lleno de manuales a los cuales se puede aacudir en caso de urgencias m´s elevadas. S´lo el Tiempo y mi tiempo dir´n a o asi estos apuntes ser´n extendidos alguna vez. a2 Estructura b´sica de un programa en C++ a2.1 El programa m´s simple aEl primer ejemplo de todo manual es el que permite escribir “Hola” en lapantalla del computador.#include <iostream.h>void main(){ cout << "Hola." << endl;} La primera l´ ınea define las instrucciones adecuadas para enviar luegoun mensaje a pantalla. La funci´n main es donde comienza a ejecutarse el oprograma; siempre debe haber una funci´n main en nuestro programa. cout oenv´ el mensaje a pantalla, y endl agrega un cambio de l´ ıa ınea al final delmensaje. 3
  • 4. 2.2 Definici´n de funciones oUno puede delegar la impresi´n del mensaje anterior a una funci´n indepen- o odiente:#include <iostream.h>void PrintHola(){ cout << "Hola." << endl;}void main(){ PrintHola();}2.3 Nombres de variables – Deben comenzar con una letra (may´sculas y min´sculas son distintas). u u – Pueden contener n´meros. u – Pueden contener el s´ ımbolo _ (underscore). – Longitud arbitraria. – No pueden corresponder a una de las 48 palabras reservadas de C++ (if, else, etc.).2.4 Tipos de variablesTodas las variables a usar deben ser declaradas de acuerdo a su tipo. Porejemplo, si usamos una variable i que sea un n´mero entero, debemos, antes ude usarla, declararla, y s´lo entonces podemos asignarle un valor: oint i;i=10; 4
  • 5. Es posible reunir las acciones de declaraci´n e inicializaci´n en una misma o ol´ ınea:int i = 10; Los tipos de variables disponibles son1 : int Enteros entre −215 = −32768 y 215 − 1 = 32767 o entre −231 = −2147483648 y 231 − 1 = 2147483647 short int short Enteros entre −215 y 215 − 1. long int long Enteros entre −231 y 231 − 1. unsigned int Enteros entre 0 y 216 − 1 o entre 0 y 232 − 1. unsigned short Enteros entre 0 y 216 − 1. unsigned long Enteros entre 0 y 232 − 1. char Caracteres. float Reales en los intervalos [−1.7 · 1038 , −0.29 · 10−38 ], [0.29 · 10−38 , 1.7 · 1038 ] (Precisi´n de unos 7 d´ o ıgitos decimales.) double Reales en los mismos intervalos que float, pero con precisi´n de 16 decimales, o o en los intervalos [−0.9 · 10308 , −0.86 · 10−308 ] y [0.86 · 10−308 , 0.9 · 10308 ], con precisi´n de o 15 decimales. Las variables tipo char alojan caracteres, debiendo inicializarse en laforma:char c = ’a’; Adem´s de las letras may´sculas y min´sculas, y s´ a u u ımbolos como &, (,:, etc., hay una serie de caracteres especiales (caracteres de escape) que esposible asignar a una variable char. Ellos son: 1 Los valores de los rangos indicados son simplemente representativos y dependen de lam´quina utilizada. a 5
  • 6. newline n horizontal tab t vertical tab v backspace b carriage return r form feed f alert (bell) a backslash single quote ’ double quote " Por ejemplo, la l´ ınea:cout << "Primera columnat Segunda columnan Segunda linea" << endl;corresponde al outputPrimera columna Segunda columnaSegunda linea2.5 Ingreso de datos desde el teclado#include <iostream.h>void main(){ int i; cout << "Ingrese un numero entero: "; cin >> i; cout << "El numero ingresado fue: " << i << endl;}2.6 Operadores aritm´ticos eExisten operadores para la suma, la resta, la multiplicaci´n, la divisi´n: o o+ - * / 6
  • 7. 2.7 Operadores relacionalesLos s´ımbolos para las relaciones de igualdad, desigualdad, menor, menor oigual, mayor y mayor o igual son:== != < <= > >= Para las relaciones l´gicas AND, OR y NOT: o&& || !2.8 Asignaciones a) Asignaci´n simple. o i = 1; b) Asignaci´n compuesta. o La expresi´n o x = x + 2 se puede reemplazar por x += 2 Existen los operadores += -= *= /= c) Operadores de incremento y decremento. La expresi´n o x = x + 1 se puede reescribir x += 1 o bien x++ An´logamente, existe el operador --. a 7
  • 8. 2.9 Conversi´n de tipos oObservemos que en una expresi´n del tipo: oint i = 3;float x = 43.8;cout << "Suma = " << x + i << endl;el computador debe sumar dos variables de tipos distintos, y por tanto debeconvertir ambas a un tipo com´n antes de efectuar la suma. Existen dos umodos de proceder: a) Conversi´n expl´ o ıcita. Insertar la expresi´n o j = float(i); Esto es bastante tedioso, por cuanto el programador debe realizar el trabajo de conversi´n personalmente. o b) Conversi´n impl´ o ıcita. El compilador realiza las conversiones de modo autom´tico, prefiriendo a siempre la conversi´n desde un tipo de variable de menor precisi´n a o o uno de mayor precisi´n (de int a double, de short a int, etc.). o Es interesante notar c´mo las conversiones impl´ o ıcitas de tipos pueden tener consecuencias insospechadas y esot´ricas. e Consideremos las tres expresiones: i) x = (1/2) * (x + a/x) ; ii) x = (0.5) * (x + a/x) ; iii) x = (x + a/x)/2 ; Si inicialmente x=0.5 y a=0.5, por ejemplo, i) entrega el valor x=0, mientras ii) y iii) entregan el valor x=1.5. Lo que ocurre es que 1 y 2 son enteros, de modo que 1/2 = 0. De acuerdo a lo que dijimos, uno esperar´ que en i), como conviven n´meros reales con enteros, los ıa u n´meros enteros fueran convertidos a reales y, por tanto, la expresi´n u o tuviera el resultado esperado, 1.5. El problema es la prioridad de las 8
  • 9. operaciones. No todas las operaciones tienen igual prioridad (las mul- tiplicaciones y divisiones se realizan antes que las sumas y restas, por ejemplo), y esto permite al compilador decidir cu´l operaci´n efectuar a o primero. Cuando se encuentra con operaciones de igual prioridad (dos multiplicaciones, por ejemplo), se procede a efectuarlas de izquierda a derecha. Pues bien, en i), la primera operaci´n es 1/2, una divisi´n entre en- o o teros, i.e. cero. En ii) no hay problema, porque todas son operaciones entre reales. Y en iii) la primera operaci´n es el par´ntesis, que es una o e operaci´n entre reales. Al dividir por 2 ´ste es convertido a real antes o e de calcular el resultado. i) a´n podr´ utilizarse, cambiando el prefactor del par´ntesis a 1.0/2.0, u ıa e una pr´ctica que ser´ conveniente adoptar como standard cuando quer- a ıa emos utilizar enteros dentro de expresiones reales, para evitar errores que pueden llegar a ser muy oscuros.3 Control de flujo3.1 if, if... else, if... else if a) if (a==b) { cout << "a es igual a b" << endl; } b) if (c!=d) { cout << "c es distinto de d" << endl; } else { cout << "c es igual a d" << endl; } c) if (e > f) { cout << "e es mayor que f" << endl; 9
  • 10. } else if (e == f) { cout << "e es igual a f" << endl; } else { cout << "e es menor que f" << endl; }3.2 Expresi´n condicional oif (a==b){ c = 1;}else{ c = 0;}se puede reemplazar porc = (a==b) ? 1 : 0;3.3 switchswitch (i){case 1: { cout << "Caso 1." << endl; } break;case 2: { cout << "Caso 2." << endl; } 10
  • 11. break;default: { cout << "Otro caso." << endl; } break;} La instrucci´n break permite que la ejecuci´n del programa salte a la o ol´ ınea siguiente despu´s de la serie de instrucciones asociadas a switch. Por eejemplo, si no existieran los break, e i=1, entonces ver´ ıamos en pantalla lasl´ ıneas Caso 1., Caso 2. y Otro caso. La instrucci´n default es opcional. o3.4 whilewhile (i < 3){ cout << i << endl; i++;}3.5 forfor (i = 1; i < 10; i++){ cout << "Valor del indice: " << i << endl;} Los argumentos segundo y tercero de for son opcionales (no los ;).Adem´s, se puede involucrar m´s de una variable en el ciclo: a afor (i=0, k=20; (i<10) && (k<100); i++, k+=6){ cout << "i + k = " << i + k << endl;} 11
  • 12. 3.6 do... whiledo{ cout << i << endl; i++;}while (i<=20);3.7 gotoExiste tambi´n en C++ una instrucci´n goto que permite saltar de un punto e oa otro del programa (goto salto; permite saltar a la l´ ınea que contiene lainstrucci´n salto:). Sin embargo, se considera una mala t´cnica de pro- o egramaci´n usar goto, y siempre se puede dise˜ar un programa evit´ndolo. o n aAltamente no recomendable.4 FuncionesLas funciones nos permiten programar partes del procedimiento por separado.Un ejemplo simple de ellas lo vimos en la subsecci´n 2.2. o4.1 Funciones tipo voidUn caso especial de funciones es aqu´l en que el programa que llama la funci´n e ono espera que ´sta le entregue ning´n valor al terminar. Por ejemplo, en la e usubsecci´n 2.2, la funci´n PrintHola simplemente imprime un mensaje en o opantalla. El resto del programa no necesita de ning´n resultado parcial uproveniente de la ejecuci´n de dicha funci´n. La definici´n de estas funciones o o odebe ir precedida de la palabra void, como en el ejemplo citado. Observemosque la funci´n main en todos nuestros ejemplos hasta ahora es una funci´n o ode tipo void tambi´n. e4.2 returnSi deseamos definir una funci´n que calcule una ra´ cuadrada, evidente- o ızmente esperamos que la funci´n nos entregue un resultado: el valor de la ra´ o ız 12
  • 13. cuadrada. En este caso hay que traspasar el valor de una variable desde lafunci´n al programa que la llam´. Esto se consigue con return. o oint numero(){ int i = 3; return i;}void main(){ cout << "Llamamos a la funcion" << endl; cout << "El numero es: " << numero() << endl; int i = 5; i = i + numero(); cout << "El numero mas 5 es: " << i << endl;} En este caso, la funci´n simplemente entrega el valor de la variable interna oi, es decir 3, el cual puede ser usado para salida en pantalla o dentro deoperaciones matem´ticas corrientes. a Dos observaciones utiles: ´ a) La declaraci´n de la funci´n lleva antepuesto el tipo de variable que o o la funci´n entrega. En el ejemplo, la variable entregada es un entero, o i, y la declaraci´n debe ser por tanto: int numero(). Podemos tener o funciones tipo double, char, long, etc., de acuerdo al tipo de variable que corresponde a return. b) La variable i que se usa dentro de main() y la que se usa dentro de numero() son distintas. A pesar de que tienen el mismo nombre, se pueden usar independientemente como si se llamaran distinto. Se dice que i es una variable local.4.3 Funciones con par´metros aVolviendo al ejemplo de la ra´ cuadrada, nos gustar´ llamar a esta funci´n ız ıa ocon un par´metro (el n´mero al cual se le va a calcular la ra´ cuadrada). a u ızExisten dos modos de transferir par´metros a una funci´n: a o 13
  • 14. a) Por valor. int funcion(int i) { i+=4; return i; } void main() { i = 3; cout << "El valor de la funcion es " << funcion(i) << endl; cout << "El valor del parametro es " << i << endl; } El resultado en pantalla es: El valor de la funcion es 7 El valor del parametro es 3 La funci´n funcion entrega el valor del par´metro m´s 4. Usamos o a a el mismo nombre (i) para las variables en main y funcion, pero son variables locales, as´ que no interfieren. Lo importante es notar que ı cuando se llama la funci´n, la reasignaci´n del valor de i [i+=4] ocurre o o s´lo para la variable local en funcion; el par´metro externo mantiene o a su valor. Lo que ha ocurrido es que la funci´n copia el valor de la variable externa o i en una nueva variable (que tambi´n se llama i, pero est´ en otra e a direcci´n de memoria). El valor con el que trabaja la funci´n es la o o copia, manteniendo inalterada la variable original.b) Por referencia. int funcion(int & i) { i+=4; 14
  • 15. return i; } void main() { i = 3; cout << "El valor de la funcion es " << funcion(i) << endl; cout << "El valor del parametro es " << i << endl; } ´ Este es el mismo ejemplo anterior, pero modificando la declaraci´n del o argumento en funcion. El efecto es que en vez de traspasarle a funcion el valor del par´metro, se le entrega la direcci´n de memoria de dicha a o variable, permiti´ndosele de este modo modificar su valor. El resultado e en pantalla del ultimo programa ser´: ´ a El valor de la funcion es 7 El valor del parametro es 7 El paso de par´metros por referencia debe ser usado con sabidur´ a ıa. De hecho el ejemplo presentado es poco recomendable. Un caso m´s a util es el intercambiar entre s´ el valor de dos variables, digamos a1=1 ´ ı y a2=3. Luego de ejecutar la funci´n queremos que a1=3 y a1=1, es o decir, precisamente que el valor de las variables originales cambie. El uso de par´metros por referencia es la t´cnica a usar en esta situaci´n. a e o4.4 Par´metros default aC++ permite que omitamos algunos par´metros de la funci´n llamada, la a ocual reemplaza los valores omitidos por otros predeterminados. Tomemospor ejemplo la funci´n de la subsecci´n 4.3, y modifiqu´mosla de modo que o o esi no le entregamos par´metros, asuma que el n´mero entregado fue 5: a uint funcion(int i = 5){ i+=4; 15
  • 16. return i;}void main(){ cout << "El resultado default es " << funcion() << endl; int i = 3; cout << "Cuando el parametro vale " << i << " el resultado es " << funcion(i) << endl;} El output correspondiente es:El resultado default es 9Cuando el parametro vale 3 el resultado es 74.5 Alcance, visibilidad, tiempo de vidaCon el concepto de funci´n hemos apreciado que es posible que coexistan ovariables con el mismo nombre en puntos distintos del programa, y que sig-nifiquen cosas distintas. Conviene entonces tener en claro tres conceptos queest´n ligados a esta propiedad: aAlcance La secci´n del c´digo durante la cual el nombre de una variable o o puede ser usado. Comprende desde la declaraci´n de la variable hasta o el final del cuerpo de la funci´n donde es declarada. o Si la variable es declarada dentro de una funci´n es local . Si es definida o fuera de todas las funciones (incluso fuera de main), la variable es global.Visibilidad Indica cu´les de las variables actualmente al alcance pueden ser a accesadas. En nuestros ejemplos (subsecci´n 4.3), la variable i en main o a´n est´ al alcance dentro de la funci´n funcion, pero no es visible, y u a o por eso es posible reutilizar el nombre.Tiempo de vida Indica cu´ndo las variables son creadas y cu´ndo destru- a a idas. En general este concepto coincide con el alcance (las variables son creadas cuando son declaradas y destruidas cuando la funci´n dentro de o la cual fueron declaradas termina), salvo porque es posible definir: (a) variables din´micas, que no tienen alcance, sino s´lo tiempo de vida; a o 16
  • 17. (b) variables est´ticas, que conservan su valor entre llamadas sucesivas a de una funci´n (estas variables tienen tiempo de vida mayor que su o alcance).4.6 Recursi´n oC++ soporta un tipo especial de t´cnica de programaci´n, la recursi´n, que e o opermite que una funci´n se llame a s´ misma. Esto permite definir de modo o ımuy compacto una funci´n que calcule el factorial de un n´mero entero n. o uint factorial(int n){ return (n<2) ? 1: n * factorial(n-1);}5 Matrices5.1 Declaraci´n e inicializaci´n o oPodemos declarar (e inicializar inmediatamente) matrices de enteros, realesde doble precisi´n, caracteres, etc., seg´n nuestras necesidades. o uint a[5];double r[3] = {3.5, 4.1, -10.8};char palabra[5]; Una vez declarada la matriz (digamos a[5]), los valores individuales seaccesan con a[i], con i desde 0 a 4. Por ejemplo, podemos inicializar loselementos de la matriz as´ ı:a[0] = 3;a[3] = 5; ...o si queremos ingresarlos desde el teclado:for (i = 0; i < 5; i++){ cin >> a[i];} 17
  • 18. Y si deseamos escribirlos en pantalla:for (i = 0; i < 5; i++){ cout >> a[i];}5.2 Matrices como par´metros de funciones aSi deseamos, por ejemplo, dise˜ar una funci´n que mande los elementos de n ouna matriz a pantalla:void PrintMatriz(int i, double a[]){ for (int j = 0; j < i; j++) { cout << "Elemento " << j << " = " << a[j] << endl; }}void main(){ double matriz[5] = {3.5, 5.2, 2.4, -0.9, -10.8}; PrintMatriz(5, matriz);} Observemos que la funci´n debe recibir dos par´metros, uno de los cuales o aes la dimensi´n de la matriz. Esto se debe a que cuando las matrices son ousadas como par´metros la informaci´n de su dimensi´n no es traspasada, a o oy debe ser comunicada independientemente. Una ligera optimizaci´n al pro- ograma anterior es modificar main a:void main(){ int dim = 5; double matriz[dim] = {3.5, 5.2, 2.4, -0.9, -10.8}; PrintMatriz(dim, matriz);} 18
  • 19. De este modo, si eventualmente cambiamos de opini´n y deseamos trabajar ocon matrices de longitud distinta, s´lo hay que modificar una l´ o ınea de c´digo o(la primera) en todo el programa, el cual puede llegar a ser bastante largopor cierto. (En el ejemplo, tambi´n habr´ que cambiar la l´ e ıa ınea de inicial-izaci´n de la matriz, porque asume que la matriz requiere s´lo 5 elementos, o opero de todos modos deber´ ser clara la enorme conveniencia —en progra- ıamas m´s generales— de definir la dimensi´n de la matriz como una variable a oindependiente.)5.3 Matrices multidimensionalesEs f´cil declarar e inicializar matrices de m´s de una dimensi´n: a a odouble array[10][8];int array[2][3] = {{1, 2, 3}, {4, 5, 6}};5.4 Matrices de caracteres: cadenas (strings)Una cadena es una matriz de caracteres que termina con el char nulo: ’0’.char palabra[5] = {’H’, ’o’, ’l’, ’a’, ’0’};Cuando enviamos esta matriz a pantalla:for (i = 0; i < 5; i++){ cout << palabra[i];}El resultado es Hola. Es equivalente esto a la instrucci´n ya conocida ocout << "Hola". De hecho, la declaraci´n de palabra podr´ haberse es- o ıacrito:char palabra[5] = "Hola"; Las l´ ıneas de texto, entonces, no corresponden sino a matrices de car-acteres. Se entiende entonces la necesidad de introducir el char especial’0’. En efecto, toda matriz en C++ debe tener una dimensi´n definida. oSin embargo, las palabras o las l´ ıneas de texto que se nos pudiera ocurrir uti-lizar pueden tener una longitud arbitraria, lo cual genera un conflicto. C++resuelve el problema aceptando que estas matrices de caracteres tengan lon-gitud arbitraria, pero adoptando la convenci´n de se˜alar d´nde terminan. o n o 19
  • 20. 5.4.1 string.hUna serie de funciones utiles para manejar palabras (convertir todas las letras ´en may´sculas, contar el n´mero de caracteres, etc.) son accesibles agregando u ual comienzo del programa la l´ ınea:#include <string.h> Por ejemplo: a) strlen(a) entrega el n´mero de caracteres de la cadena a (como un u humano lo entender´ es decir, sin incluir ’0’). ıa, b) strncpy(a,b) copia la cadena b en a. (Podr´ ıamos esperar que, como cuando intervienen variables num´ricas, esto se realizara con a=b, pero e no es as´ ı.)5.4.2 Input/Output de cadenasYa sabemos que la salida a pantalla de cadenas se realiza con cout y <<simplemente, como con todos los dem´s tipos de variables. a El ingreso por teclado de cadenas es m´s problem´tico debido a la longitud a aindeterminada de la matriz. La soluci´n m´s f´cil es: o a achar a[30];cout << "Ingrese una palabra: ";cin >> a;La idea es que la matriz sea suficientemente grande (30 caracteres en estecaso) para que una palabra cualquiera quepa holgadamente. Las dificultadesque aparecen son dos: a) La longitud del input puede ser demasiado grande. El problema de esto es que un input demasiado grande aloja caracteres en direcciones de memoria sobre los cuales no se tiene ningun control, con consecuencias posiblemente catastr´ficas en aplicaciones suficientemente complicadas. o La soluci´n ser´ aumentar el tama˜o de la matriz (lo cual no se puede o ıa n hacer hasta infinito en todo caso). b) S´lo se puede ingresar una palabra a la vez. Esto es porque C++ con- o sidera a los espacios en blanco como fin de input. Esto no es necesari- amente una desventaja, porque si queremos ingresar por teclado varios 20
  • 21. valores de una sola vez, basta separarlos por espacios. Pero cuando se trata de texto no necesariamente queremos ingresar palabras individ- uales. Una soluci´n al problema b) es ingresar l´ o ıneas completas (i.e. hasta queaparezca un ’n’ o Enter). Claro que esto no soluciona el problema delcontrol de la longitud del texto (una l´ ınea podr´ ser m´s larga que cualquier ıa alongitud preconcebida), problema que debe ser tratado por separado. El siguiente programa muestra un ejemplo de soluci´n para ambas situa- ociones:int buffersize = 512;char inputBuffer[buffersize];if (cin.getline(inputBuffer,buffersize-1)){ cout << inputBuffer << endl;}else{ cout << "Demasiado larga: " << inputBuffer << endl; while (cin.clear(), !cin.getline(inputBuffer, buffersize-1)) { cout << " y tambien: " << inputBuffer << endl; } cout << " y finalmente: " << inputBuffer << endl;} En este programa, cin.getline(inputBuffer,buffersize) recibe unal´ ınea desde el teclado hasta que encuentra un fin de l´ ınea, con un m´ximo ade buffersize-1 caracteres, a˜adiendo al final un ’0’. Esta funci´n es n ofalsa si algo sali´ mal en el proceso de ingreso de datos (por ejemplo, si se oingresaron m´s caracteres que la longitud establecida). a cin.clear() resetea el estado del mecanismo de input, prepar´ndolo para auna nueva sesi´n de ingreso. o6 ClasesC++ dispone de una serie de tipos de variables con los cuales nos est´ per- amitido operar: int, double, char, etc. Creamos variables de estos tipos y 21
  • 22. luego podemos operar con ellos:int x, y;x = 3;y = 6;int z = x + y; No hay, sin embargo, en C++, una estructura predefinida que corre-sponda a n´meros complejos, vectores de dimensi´n n o matrices, por ejem- u oplo. Y sin embargo, nos agradar´ disponer de n´meros complejos que ıa upudi´ramos definir como ez = (3,5);w = (6,8);y que tuvieran sentido las expresionesa = z + w;b = z * w;c = z / w;d = z + 3;e = modulo(z);f = sqrt(z); Todas estas expresiones son completamente naturales desde el punto devista matem´tico, y ser´ bueno que el lenguaje las entendiera. Esto es a ıaimposible en el estado actual, pues, por ejemplo, el signo + es un operador queespera a ambos lados suyos un n´mero. Sumar cualquier cosa con cualquier ucosa no significa nada necesariamente, as´ que s´lo est´ permitido operar ı o acon n´meros. Pero los humanos sabemos que los complejos son n´meros. u u¿C´mo dec´ o ırselo al computador? ¿C´mo convencerlo de que sumar vectores oo matrices es tambi´n posible matem´ticamente, y que el mismo signo + e adeber´ servir para todas estas operaciones? ıa La respuesta es: a trav´s del concepto de clases. Lo que debemos hacer ees definir una clase de n´meros complejos. Llam´mosla Complejo. Una u evez definida correctamente, Complejo ser´ un tipo m´s de variable que el a acompilador reconocer´, igual que int, double, char, etc. Y ser´ tan f´cil a a aoperar con los Complejos como con todos los tipos de variables preexistentes.Esta facilidad es la base de la extensibilidad de que es capaz C++, y por tantode todas las propiedades que lo convierten en un lenguaje muy poderoso. 22
  • 23. Las clases responden a la necesidad del programador de construir objetoso tipos de datos que respondan a sus necesidades. Si necesitamos trabajarcon vectores de 5 coordenadas, ser´ natural definir una clase que corresponda aa vectores con 5 coordenadas; si se trata de un programa de administraci´n de opersonal, la clase puede corresponder a un empleado, con sus datos personalescomo elementos. Si bien es cierto uno puede trabajar con clases en el contexto de ori-entaci´n al procedimiento, las clases muestran con mayor propiedad su po- otencial con la orientaci´n al objeto, donde cada objeto corresponde a una oclase. Por ejemplo, para efectuar una aplicaci´n para Windows, la ventana oprincipal, las ventanas de los archivos abiertos, la barra de men´, las cajas ude di´logo, los botones, etc., cada uno de estos objetos estar´ asociado a una a aclase.6.1 Definici´n oDigamos que queremos una clase para representar los empleados de una em-presa. Llam´mosla Persona. La convenci´n aceptada es que los nombres de e olas clases comiencen con may´scula. Esto es porque las clases, recordemos, ucorresponder´n a tipos de variables tan v´lidos como los internos de C++ a a(int, char, etc.). Al usar nombres con may´scula distiguimos visualmente ulos nombres de un tipo de variable interno y uno definido por el usuario. La estructura m´ ınima de la definici´n de la clase Persona es: oclass Persona{}; Todas las caracter´ ısticas de la clase se definen entre los parent´sis cursivos. e6.2 MiembrosSe denomina miembros de una clase a todas las variables y funciones declaradasdentro de una clase. Por ejemplo, para personas, es natural caracterizarlaspor su nombre y su edad. Y si se trata de empleados de una empresa, esnatural tambi´n tener una funci´n que entregue su sueldo: e o 23
  • 24. class Persona{ char nombre[20]; int edad; double sueldo();} Los miembros de una funci´n pueden tener cualquier nombre, excepto el onombre de la propia clase dentro de la cual se definen.6.3 Miembros p´ blicos y privados uUna clase distingue informaci´n (datos o funciones) privada (accesible s´lo a o ootros miembros de la misma clase) y p´blica (accesible a funciones externas ua la clase). La parte privada corresponde a la estructura interna de la clase,y la parte p´blica a la implementaci´n (t´ u o ıpicamente funciones), que permitela interacci´n de la clase con el exterior. o Consideremos ahora nuestro deseo de tener una clase que representen´meros complejos. Un n´mero complejo tiene dos n´meros reales (parte u u ureal e imaginaria), y ´sos son elementos privados —es decir, parte de su es- etructura interna. Sin embargo, nos gustar´ poder modificar y conocer esas ıacantidades. Eso s´lo puede hacerse a trav´s de funciones p´blicas. o e uclass Complejo{private: double real, imaginaria;public: void setreal(double); void setimag(double); double getreal(); double getimag();};En este ejemplo, los miembros privados son s´lo variables, y los miembros o u o ´p´blicos son s´lo funciones. Este es el caso t´ ıpico, pero puede haber variablesy funciones de ambos tipos. 24
  • 25. 6.4 Operador de selecci´n (.) oHemos definido una clase de n´meros complejos y funciones que nos per- umiten conocer y modificar las partes real e imaginaria. ¿C´mo se usan estos oelementos? Consideremos el siguiente programa de ejemplo:class Complejo{private: double real, imaginaria;public: void setreal(double); void setimag(double); double getreal(); double getimag();};void main(){ Complejo z, w; z.setreal(3); z.setimag(2.8); w.setreal(1.5); w.setimag(5); cout << "El primer n’umero complejo es: " << z.getreal() << " + i*" << z.getimag() << endl; cout << "El segundo es: " << w.getreal() << " + i*" << z.getimag() << endl;}Vemos en la primera l´ınea de main c´mo la clase Complejo se usa del mismo omodo que usar´ ıamos int o double. Ahora Complejo es un tipo de variabletan v´lido como los tipos predefinidos por C++. Una vez definida la vari- aable, el operador de selecci´n (.) permite acceder a las funciones p´blicas o ucorrespondientes a la clase Complejo, aplicadas a la variable particular quenos interesa: z.setreal(3) pone en la parte real del Complejo z el n´mero u3, y w.setreal(1.5) hace lo propio con w. 25
  • 26. 6.5 Implementaci´n de funciones miembros oYa sabemos c´mo declarar funciones miembros en el interior de la clase y oc´mo usarlas. Ahora veamos c´mo se implementan. o ovoid Complejo::setreal(double x){ real = x;}void Complejo::setimag(double x){ imag = x;}double Complejo::getreal(){ return real;}double Complejo::getimag(){ return imaginaria;}Como toda funci´n, primero va el tipo de la funci´n (void o double en los o oejemplos), luego el nombre de la funci´n y los argumentos. Finalmente la oimplementaci´n. Lo diferente es que el nombre va precedido del nombre de ola clase y el operador “::” .6.6 ConstructorAl declarar una variable, el programa crea el espacio de memoria suficientepara alojarla. Cuando se trata de variables de tipos predefinidos en C++esto no es problema, pero cuando son tipos definidos por el usuario C++debe saber c´mo construir ese espacio. La funci´n que realiza esa tarea se o odenomina constructor. El constructor es una funci´n p´blica de la clase, que tiene el mismo o unombre que ella. Agreguemos un constructor a la clase Complejo: 26
  • 27. class Complejo{private: double real,imaginaria;public: Complejo(double,double); void setreal(double); void setimag(double); double getreal(); double getimag();};Complejo::Complejo (double x, double y): real(x), imaginaria(y){}Definir el constructor de esta manera nos permite crear en nuestro pro-grama variables de tipo Complejo y asignarles valores sin usar setreal() osetimag():Complejo z (2, 3.8);Complejo w = Complejo(6.8, -3); En el constructor se inicializan las variables internas que nos interesainicializar al momento de crear un objeto de esta clase. Si una de las variables internas a inicializar es una cadena de caracteres,hay que inicializarla de modo un poco distinto. Por ejemplo, si estamos ha-ciendo una clase Persona que s´lo tenga el nombre de una persona, entonces opodemos definir la clase y su constructor en la forma:class Persona{private: char nombre[20];public: Persona(char []);}; 27
  • 28. Persona::Persona(a[]){ strcpy(nombre,a);} Si uno no especifica el constructor de una clase C++ crea uno default,pero en general ser´ insuficiente para cualquier aplicaci´n realmente pr´ctica. a o aEs una mala costumbre ser descuidado y dejar estas decisiones al computador.6.7 DestructorAs´ como es necesario crear espacio de memoria al definir una variable, ıhay que deshacerse de ese espacio cuando la variable deja de ser necesaria.En otras palabras, la clase necesita tambi´n un destructor . Si la clase es eComplejo, el destructor es una funci´n p´blica de ella, llamada ~Complejo. o uclass Complejo{private: double real, imaginaria;public: Complejo(double,double); ~Complejo(void); void setreal(double); void setimag(double); double getreal(); double getimag();};Complejo::Complejo (double x, double y): real(x), imaginaria(y){}Complejo::~Complejo(void){} Como con los constructores, al omitir un destructor C++ genera unodefault, pero es una mala costumbre. . . , etc. 28
  • 29. 6.8 Matrices de clasesUna clase es un tipo de variable como cualquier otro de los predefinidos enC++. Es posible construir matrices con ellas, del mismo modo que unotiene matrices de enteros o caracteres. La unica diferencia con las matrices ´usuales es que no se pueden s´lo declarar, sino que hay que inicializarlas osimult´neamente. Por ejemplo, si queremos crear una matriz que contenga a2 n´meros complejos, la l´ u ıneaComplejo z[2];es incorrecta, pero s´ es aceptable la l´ ı ıneaComplejo z[2] = {Complejo(3.5,-0.8), Complejo(-2,4)};7 SobrecargaPara que la definici´n de nuevos objetos sea realmente util, hay que ser ca- o ´paz de hacer con ellos muchas acciones que nos ser´ naturales. Como ya ıancomentamos al introducir el concepto de clase, nos gustar´ sumar n´meros ıa ucomplejos, y que esa suma utilizara el mismo signo + de la suma usual. Oextraerles la ra´ cuadrada, y que la operaci´n sea tan f´cil como escribir ız o asqrt(z). Lo que estamos pidiendo es que el operador + o la funci´n sqrt() osean polim´rficos, es decir, que act´e de distinto modo seg´n el tipo de ar- o u ugumento que se le entregue. Si z es un real, sqrt(z) calcular´ la ra´ de un a ızn´mero real; si es complejo, calcular´ la ra´ de un n´mero complejo. u a ız u La t´cnica de programaci´n mediante la cual podemos definir funciones e opolim´rficas se llama sobrecarga. o7.1 Sobrecarga de funcionesDigamos que la ra´ cuadrada de un n´mero complejo a + ib es (a/2) + i(b/2). ız u(Es m´s complicado en realidad, pero no queremos escribir las f´rmulas a oahora.) Para sobrecargar la funci´n sqrt() de modo que acepte n´meros com- o uplejos basta definirla as´ ı: 29
  • 30. Complejo sqrt(Complejo z){ return Complejo (z.getreal()/2, z.getimag()/2);}Observemos que definimos una funci´n sqrt que acepta argumentos de tipo oComplejo, y que entrega un n´mero del mismo tipo. Cuando pidamos la ra´ u ızde un n´mero, el computador se preguntar´ si el n´mero en cuesti´n es un u a u oint, double, float o Complejo, y seg´n eso escoger´ la versi´n de sqrt que u a ocorresponda. Con la definici´n anterior podemos obtener la ra´ cuadrada de un n´mero o ız ucomplejo simplemente con las instrucciones:Complejo z(1,3);Complejo raiz = sqrt(z);7.2 Sobrecarga de operadores¿C´mo le decimos al computador que el signo + tambi´n puede aceptar o en´meros complejos? La respuesta es f´cil, porque para C++ un operador u ano es sino una funci´n, y la acci´n de sobrecargar que ya vimos sirve en este o ocaso tambi´n. La sintaxis es: eComplejo operator + (Complejo z, Complejo w){ return Complejo (z.getreal() + w.getreal(), z.getimag() + w.getimag());}7.3 Coerci´n oSabemos definir a + b, con a y b complejos. Pero ¿qu´ pasa si a o b son eenteros? ¿O reales? Pareciera que tendr´ ıamos que definir no s´lo oComplejo operator + (Complejo a, Complejo b);sino tambi´n todas las combinaciones restantes: eComplejo operator + (Complejo a, int b);Complejo operator + (Complejo a, float b);Complejo operator + (int a, Complejo b); 30
  • 31. etc´tera. e En realidad esto no es necesario. Por cierto, un n´mero real es un n´mero u ucomplejo con parte imaginaria nula, y es posible hacerle saber esto a C++,usando la posibilidad de definir funciones con par´metros default. Basta adeclarar (en el interior de la clase) el constructor de los n´meros complejos ucomoComplejo (double, double = 0);Esto permite definir un n´mero complejo con la instrucci´n: u oComplejo c = Complejo(3.5);resultando el n´mero complejo 3.5 + i · 0. Y si tenemos una l´ u ınea del tipo:Complejo c = Complejo(3,2.8) + 5;el computador convertir´ impl´ a ıcitamente el entero 5 a Complejo (sabe comohacerlo porque el constructor de n´meros complejos acepta tambi´n un solo u eargumento en vez de dos), y luego realizar´ la suma entre dos complejos, que aes entonces la unica que es necesario definir. ´8 PunterosUna de las ventajas de C++ es permitir el acceso directo del programadora zonas de memoria, ya sea para crearlas, asignarles un valor o destruirlas.Para ello, adem´s de los tipos de variables ya conocidos (int, double, clases), aC++ proporciona un nuevo tipo: el puntero. El puntero no contiene el valorde una variable, sino la direcci´n de memoria en la cual dicha variable se oencuentra. Un peque˜o ejemplo nos permite ver la diferencia entre un puntero y la nvariable a la cual ese puntero “apunta”:void main(){ int i = 42; int * p_i = &i; cout << "El valor del puntero es: " << p_i << endl; cout << "Y apunta a la variable: " << *p_i << endl;} 31
  • 32. En este programa definimos una variable i entera, y luego un puntero aesa variable, que en este caso denominamos p_i. Observemos la presenciade los s´ ımbolos * y &. Al ejecutar este programa, veremos en pantalla unaprimera l´ınea que nos da el valor del puntero, donde encontraremos alg´n un´mero hexadecimal imposible de determinar a priori, y que corresponde a ula direcci´n de memoria donde qued´ ubicada la variable i. La segunda l´ o o ıneanos da el valor de la variable que est´ en esa direcci´n de memoria: 42. a o Los punteros tienen gran importancia cuando de manejar datos din´micos ase trata, es decir, objetos que son creados durante la ejecuci´n del programa, oen n´mero imposible de predecir al momento de compilar. Por ejemplo, una uaplicaci´n Windows normal que crea una, dos, tres, etc. ventanas a medida oque uno abre archivos. En este caso, cada ventana es un objeto din´mico, acreado durante la ejecuci´n, y la unica forma de manejarlo es a trav´s de un o ´ epuntero a ese objeto.9 HerenciaHerencia es el mecanismo mediante el cual es posible definir clases a partirde otras, preservando parte de las propiedades de la primera y agregando omodificando otras. Por ejemplo, si definimos la clase Persona, toda Persona tendr´ una avariable miembro que sea su nombre. Si definimos una clase Hombre, tambi´neser´ Persona, y por tanto deber´ tener nombre. Pero adem´s puede tener a ıa aesposa. Y ciertamente no toda Persona tiene esposa. S´lo un Hombre. o C++ provee mecanismos para implementar estas relaciones l´gicas y opoder definir una clase Hombre a partir de Persona. Lo vemos en el siguienteejemplo:class Persona{private: char nombre[20];public: Persona(char [] = ""); ~Persona(void); char getname();} 32
  • 33. class Hombre : public Persona{private: char esposa[20];public: Hombre(char a[]) : Persona(a) { }; char getwife(); void setwife();} Primero definimos una clase Persona que tiene nombre. Luego definimosuna clase Hombre a partir de Persona (con la l´ınea class Hombre : publicPersona). Esto permite de modo autom´tico que Hombre tenga tambi´n una a evariable nombre. Y finalmente, dentro de la clase Hombre, se definen todasaquellas caracter´ ısticas adicionales que una Persona no tiene pero un Hombres´ esposa, y funciones miembros para modificar y obtener el nombre de ella. ı: Un ejemplo de uso de estas dos clases:Persona cocinera("Maria");Hombre panadero("Claudio");panadero.setwife("Estela");cout << cocinera.getname() << endl;cout << panadero.getname() << endl;cout << panadero.getwife() << endl; Observemos que panadero tambi´n tiene una funci´n getname(), a pe- e osar de que la clase Hombre no la define expl´ ıcitamente. Esta funci´n se ha oheredado de la clase de la cual Hombre se ha derivado, Persona. 33