EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
1
Notas Preliminares Introducción a la Programación en C++ Estructura de un programa en “C”
Palabras reservadas en C++ Tipos de datos en C++ Tipos de datos numéricos reales Caracteres en C++ Identificadores en C++ Literales en C++ Literales enteros en base octal Literales enteros en base hexadecimal hexadecimal Literal numérico real en C++ Literal de cadena de caracteres en C++ Variables y constantes en C++ Declaraciones de constantes en C++ Operadores C++ Operadores aritméticos Operadores relacionales y lógicos Operadores a nivel de bits Operadores de asignación. Operador condicional Otros operadores Operador de dirección Operador de indirección Operador referencia a Operador global y de resolución de ámbito Prioridad y orden de evaluación de los operadores en C++ Casting. Conversión entre tipos de datos en C++ Estructura de un programa C++ using namespace std; int main (void) Salida con formato en C++. Manipuladores Leer caracteres y cadenas de caracteres en C++ Método get() para leer un carácter Método getline() para leer una cadena de caracteres Limpiar el Buffer del Teclado Sentencias de iteración – Ciclos Ciclos repetitivos Sentencia For Sentencia while Sentencia do – while while Generar Números Aleatorios en C++ Enum Funciones en C++. Ambito de una variable en C++ Sobrecarga de Funciones en C++ C ++ Arrays / Vectores /Arreglos en C++ Vectores Bidimensionales o Matrices Ordenamiento de Vectores Ordenamiento Por Selección Selección (Selection Sort) Sort) Ordenamiento BubbleSort o Burbuja o Intercambio Directo Ordenamiento Por Inserción Directa Método De Ordenamiento Por Inserción Binaria Ordenamiento por el Método Shell Ordenamiento Heap Sort Búsqueda de elementos en un Vector
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
3 3 5 5 6 7 7 8 9 9 10 10 11 11 11 11 12 14 15 15 16 17 17 17 18 18 19 19 21 22 23 23 25 26 27 29 29 a 31 31 33 34 a 47 47 a 60
2
Búsqueda binaria Archivos Archivos de entrada Archivos de salida Registros / Data Structures / Estructuras Tratamiento de Cadenas Cadenas CHAR como "arreglos o vector vector de char", "cadenas", o "cstring". "cstring". C++ String Librería math.h Punteros Clases Constructores. Destructores. Herencia Herencia Múltiple Cadena de Herencia Polimorfismo Templates Introducción a Visual C++ Builder de Embarcadero Embarcadero RAD Studio XE series Conceptos básicos Visual. Eventos o acciones (sobre un componente): Conversión de tipos: Ventanas de mensaje Pedir datos al usuario en ventanas: Ampliación llamadas a cuadros de diálogo: Construcción de una aplicación con dos formularios. Mensajes progressbar1 Timer Uso de grilla StringGrid Pizarra de dibujo Eventos del Mouse: Dibujar en la Pizarra: Uso del Timer y posición del objeto: Eventos del teclado: dirección de nave. Animación. Protector de pantalla uso de componentes de texto. memo uso de componentes de texto. richedit y actionlist Labels. Base de datos Acceso con base de datos Acces desde FireDAC Acceso a taboas utilizando ADO Componentes de datos en el formulario principal Acceso a base de datos SQlite desde una aplicación móvil. Lista de tareas. Ejercicios / Guía de Trabajos Prácticos Bibliografía
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
60 a 62 62 63 75 88 90 104 a 132
132 136 a 167
168 194
3
Notas Preliminares La Programación es el arte de dar soluciones a los problemas para que la computadora pueda ejecutarlas. La gran parte del esfuerzo en programar es buscar soluciones y refinarlas. Este apunte es para alguien que nunca ha programado antes, pero que está dispuesto a trabajar duro para aprender. Asimismo, le ayudará a comprender los principios y adquirir los conocimientos prácticos de la programación usando el lenguaje de programación C++. ¿Por qué C++? No se puede aprender a programar sin un lenguaje de programación, y C++ apoya directamente los principales conceptos y técnicas que se utilizan en el mundo real del software. C++ es uno de los lenguajes de programación más ampliamente utilizados. La mayoría de los conceptos de programación pueden utilizarse directamente en otros lenguajes, como C#, Fortran, PhP y Java. Por último, C++ es frecuente elegirlo como lenguaje para escribir código elegante y eficiente. La hipótesis fundamental es desear escribir los programas para el uso de otros, y de hacerlo con responsabilidad, proporcionando un buen nivel de calidad de todo el sistema, es decir, lograr un muy buen nivel de profesionalismo. La programación se adquiere haciendo programas. En este tipo de programación es similar a la de otras actividades con un componente práctico. Las personas no pueden aprender a nadar, a tocar un instrumento musical, o conducir un coche solo con leer un libro. Todos debemos practicar. No se puede aprender a programar sin leer y escribir bastante código. Se necesita hacer los ejercicios y acostumbrarse a las herramientas para escribir, compilar y ejecutar los programas.
Introducción a la Programación en C++ a) Introducción Teórica Creador: Dennis Ritchie (Laboratorios Bell) en 1972, cuando trabajaba junto con Ken Thompson diseño del sistema operativo UNIX. El „C‟ se creó como herramienta para programadores, en consecuencia su principal objetivo es ser un lenguaje
útil. C++ es un lenguaje de programación creado a mediados de los años 1980 por BJarne Stroustrup. La intención de su creación fue extender al exitoso lenguaje de programación C con mecanismos que permitan la manipulación de objetos.
Características: El “C” es un lenguaje de programación de “alto nivel” (alto nivel quiere decir “próximo al lenguaje humano”), pero con características de “bajo nivel” (bajo nivel= próximo al lenguaje máquina).
Es de ALTO NIVEL porque es racional, estructurado y fácil de aprender. Es de BAJO NIVEL porque permite trabajar con “bits”, registros de la C.P.U. y posiciones de memoria. ¿Por qué el “C”?
El lenguaje „C‟ es poderoso y flexible: la mayor parte del sistema operativo UNIX fue escrito en „C‟. Incluso están escritos en „C‟ los compiladores e int érpretes de otros lenguajes, como FORTRAN, APL,
PASCAL, LISP, LOGO y BASIC.
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
4
El lenguaje „C‟ es “amistoso” porque es lo suficientemente estructurado para ejercer buenos hábitos de
programación. Es el lenguaje de programación más utilizado por el programador de sistemas.
Estructura de un programa en “C”: El „C‟ es gráficamente:
CÓDIGO FUENTE: es el programa que nosotros escribimos, se graba con la extensión CPP CÓDIGO OBJETO: es el programa fuente pero traducido a lenguaje máquina (sucesión de ceros y unos), se graba con la extensión OBJ PROGRAMA EJECUTABLE: es el programa objeto más las “librerías del C”, se graba con la extensión EXE. Y no necesita el programa que hemos utilizado para crearlo, para poder ejecutarlo. El código Objeto que genera un compilador de “C”, es casi tan eficiente (rápido) como si lo hubiéramos escrito en lenguaje ENSAMBLADOR (lenguaje de programación más próximo al lenguaje máquina).
El presente apunte está orientado a la construcción de programas sobre el compilador Dev C++ y Embaracdero XE8 C++ Rad Studio
Palabras reservadas en C++ Las palabras reservadas son identificadores predefinidos que tienen significados especiales y no pueden usarse como identificadores creados por el usuario en los programas. Las palabras reservadas de C++ pueden agruparse en 3 grupos. El primero contiene las palabras de C y que C++ como evolución de C también contiene:
auto const double float int short struct unsigned break continue else for long signed switch void case default enum goto register sizeof typedef volatile char do extern if return static union while Palabras que no provienen de C y que, por tanto, solo utiliza C++:
asm dynamic_cast namespace reinterpret_cast try bool explicit new static_cast typeid catch false operator template typename class friend private this using const_cast inline public throw virtual delete mutable protected true wchar_t
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
5
Las siguientes palabras reservadas se han añadido como alternativas para algunos operadores de C++ y hacen los programas más legibles y fáciles de escribir:
and bitand compl not_eq or_eq xor_eq and_eq bitor not or xor
Tipos de datos en C++ Los tipos de datos en C++ se clasifican en primitivos y derivados. Los tipos de datos primitivos son los que están definidos dentro del lenguaje. Los tipos de datos derivados se forman a partir de los tipos primitivos. En este tema veremos los tipos primitivos y en temas siguientes estudiaremos los tipos derivados. Los tipos de datos primitivos en C++ son: numéricos enteros, numéricos reales, tipo lógico y tipo carácter ampliado.
Tipos de datos C++ numéricos enteros El tipo de dato numérico entero es un subconjunto finito de los números enteros del mundo real. Pueden ser positivos o negativos. En C++ los tipos de datos numéricos enteros son los siguientes:
Entero corto
Número de bytes típico 2
-32768 a 32767
int
Entero
4
-2147483648 a +2147483647
long
Entero largo
4
-2147483648 a +2147483647
Tipo de Dato
Descripción
short
Rango
char Carácter 1 -128 a 127 Con los tipos enteros pueden utilizarse los calificadores signed y unsigned. Estos calificadores indican si el número tiene signo o no. Si se usan solos, sin indicar el tipo de dato se asume int. Por ejemplo, las siguientes declaraciones son equivalentes: unsigned int x; equivale a: unsigned x; Usando estos calificadores podemos tener los siguientes tipos enteros:
Entero corto
Número de bytes típico 2
-32768 a 32767
unsigned short
Entero corto sin signo
2
0 a 65535
signed int
Entero
4
-2147483648 a +2147483647
unsigned int
Entero sin signo
4
0 a 4294967295
signed long
Entero largo
4
-2147483648 a +2147483647
unsigned long
Entero largo sin signo
4
0 a 4294967295
signed char
Carácter
1
-128 a 127
unsigned char
Carácter sin signo
1
0 a 255
Tipo de Dato
Descripción
signed short
Rango
Podemos ver que los datos enteros de tipo signed son equivalentes a los enteros sin utilizar el califi cador:
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
6
signed int a;
es equivalente a escribir
int a;
Tipos de datos numéricos reales El tipo de dato numérico real es un subconjunto finito de los números reales. Pueden ser positivos o negativos. En C++ los tipos de datos numéricos reales son los siguientes: Tipo de Dato float double
Descripción
Número de bytes típico
Rango
4
Positivos: 3.4E-38 a 3.4E38 Negativos: -3.4E-38 a -3.4E38
8
Positivos: 1.7E-308 a 1.7E308 Negativos: -1.7E-308 a -1.7E308
Real (Número en coma flotante) Real doble(Número en coma flotante de doble precisión)
long double
Real doble largo
10
Positivos: 3.4E-4932 a 1.1E4932 Negativos: -3.4E-4932 a -1.1E4932
Tipo lógico Los datos de este tipo sólo pueden contener dos valores: true ó false (verdadero ó falso). Si se muestran como enteros, el valor true toma el valor 1 y false el valor 0. Tipo de Dato
Descripción
Número de bytes típico
Rango
bool
Dato de tipo lógico
1
0, 1
Tipo carácter extendido Este tipo se utiliza para representar caracteres UNICODE. Utiliza 2 bytes a diferencia del tipo char que solo utiliza 1. Tipo de Dato
Descripción
Número de bytes típico
Rango
wchar_t
Carácter Unicode
2
0 a 65535
Caracteres en C++ El conjunto de caracteres que se pueden usar en un programa C++ para dar nombre a variables, constantes, funciones, clases, etc, etc son los siguientes: - Letras mayúsculas y minúsculas de la A(a) a la Z(z) del alfabeto inglés. - Dígitos del 0 al 9. - El carácter subrayado o guión bajo _ - Caracteres especiales y signos de puntuación : + * / = % & \ | < > ( ) [ ] { } : ; . ,
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
#
!
?
^
“
7
„
~
- Espacios en blanco : Se llaman espacios en blanco a todos los caracteres cuya misión es separar elementos de un programa. Los caracteres espacios en blanco que pueden aparecer en un programa C++ son los siguientes: el espacio en blanco tabulador horizontal tabulador vertical avance de página nueva línea - Secuencias de escape : Una secuencia de inversa seguida de una letra o de una combinación de dígitos.
escape
esta
formada
por
una
barra
Una secuencia de escape siempre representa un solo carácter aunque se escriba con dos o más caracteres. Se utilizan para realizar acciones como salto de línea o para usar caracteres no imprimibles. Las secuencias de escape definidas en C++ son:
Identificadores en C++ Los identificadores son los nombres que se les da a los objetos de un programa. Los identificadores en c++ están formados por letras y dígitos. El primer carácter debe ser una letra, considerando en este caso el carácter guión bajo ( _ ) como una letra. No pueden contener otros caracteres especiales. Ejemplo Identificadores válidos en C++:
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
8
X area
y12 suma_1 _nota nombres porc_imp
TABLA
Ejemplo Identificadores no válidos en C++: 4numeros
"x"
orden-no
contador!
nº $edad
Como norma general, un identificador debe tener los suficientes caracteres para que su significado se reconozca fácilmente, pero se debe evitar un excesivo número de caracteres. Un identificador puede tener cualquier número de caracteres, pero dependiendo del compilador utilizado, solo son significativos los n primeros caracteres. Por tanto, dos identificadores son diferentes si difieren al menos en uno de los n primeros caracteres. No se permite el uso de la ñ ni de las tildes en los identificadores, aunque sí pueden ser utilizados en comentarios. C++ diferencia mayúsculas y minúsculas, por lo tanto, nombre y Nombre son identificadores diferentes.
Literales en C++ Un literal es cualquier valor numérico, carácter o cadena de caracteres que puede pued e aparecer dentro de un programa. Por ejemplo, literales C++ válidos pueden ser: 150, 12.4, “JOSE”, etc.
Hay 4 tipos de literales en C++: numéricos enteros, numéricos reales, carácter y cadena de caracteres.
Literal numérico entero en C++ Un literal numérico entero en C++ puede expresarse en base decimal (base 10), base octal (base 8) y base hexadecimal (base 16).
literales enteros en base decimal Están formados por 1 o más dígitos del 0 al 9. El primer dígito debe ser distinto de cero. Por ejemplo: 12 4303 4 El tipo del literal es int, unsigned int ó unsigned long int. Se toma como tipo, siguiendo ese orden, aquel en el que su valor pueda ser representado. También podemos usar los sufijos U, L, UL para indicar explícitamente el tipo del literal. U indica que es del tipo unsigned int, L indica el tipo long y UL unsigned long. Por ejemplo: 1234 Tipo: int 1234U Tipo: unsigned int 1234L Tipo: long 1234UL Tipo: unsigned long
Literales enteros en base octal Están formados por 1 o más dígitos del 0 al 7. El primer dígito debe ser cero. Por ejemplo: 012 EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
9
0430 04 El tipo del literal entero en octal es int, unsigned int, long int ó unsigned long int. Se toma como tipo, siguiendo ese orden, aquel en el que su valor pueda ser representado. representado. También podemos usar los sufijos U, L, UL para indicar explícitamente el tipo del literal. Por ejemplo: 01234 Tipo: int 01234U Tipo: unsigned int 01234L Tipo: long 01234UL Tipo: unsigned long
Literales enteros en base hexadecimal Están formados por 1 o más dígitos del 0 al 9 y letras de la A a la F. Estos literales deben comenzar por 0x ó 0X. Por ejemplo: 0x1A2 0X430 0xF4 El tipo del literal entero en hexadecimal, si no se le ponen sufijos, sigue la misma regla que para los enteros enter os octales. También podemos usar los sufijos U, L, UL para indicar explícitamente el tipo del literal. Por ejemplo: 0x1A Tipo: int 0x1AU Tipo: unsigned int 0x1AL Tipo: long 0x1AUL Tipo: unsigned long
Literal numérico real en C++ Son números en base 10, que deben llevar un parte entera, un punto decimal y una parte fraccionaria. f raccionaria. Si la parte entera es cero, puede omitirse. Por ejemplo: 12.2303 -3.44 +10.33 0.456 .96 También pueden representarse utilizando la notación científica. En este caso se utiliza una E (mayúscula o minúscula) seguida del exponente. Por ejemplo, el número en notación científica 14*10-3 se escribe: 14E-3 Más ejemplos de literales numéricos reales en C++: 2.15E2 .0007E4 -50.44 5e-10 El tipo de estos literales es siempre double, a no ser que se añada el sufijo F para indicar que es float. Por ejemplo: 2.15 Tipo: double 2.15F Tipo: float
Literal de tipo carácter en C++ Contienen un solo carácter encerrado entre comillas simples. Son de tipo char.
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
10
Los caracteres posibles son todos los contenidos en la tabla ASCII. Las secuencias de escape se consideran literales de tipo carácter. Por ejemplo: 'a' '4' '\n' '\x07' Los literales de carácter ampliado (wchar_t) se forman utilizando el prefijo L. Por ejemplo: wchar_t car = L'k'
Literal de cadena de caracteres en C++ Están formados por 0 ó más caracteres encerrados entre comillas dobles. Pueden incluir secuencias de escape. Por ejemplo: “Esto es una cadena de caracteres” “Pulsa \”C\” para continuar” “T” (cadena de un solo carácter, es diferente a „t‟ que es un carácter)
Variables y constantes en C++ Declaraciones de variables en C++. Una variable se debe declarar para poder utilizarla. Una declaración de variable asocia un tipo de datos a la variable. Una declaración está formada por un tipo de dato seguido de uno o más nombres de variables, finalizando con un punto y coma. Por ejemplo: int unidades; //se declara una variable de tipo entero llamada unidades float importe, longitud; //se declaran dos variables de tipo float char opcion; //se declara una variable de tipo char En la propia declaración se puede hacer una asignación de valores iniciales: int num = 0; char guion = '-'; float longitud = 6.25;
Declaraciones de constantes en C++. Declarar una constante supone asociar un tipo de datos y un valor a la constante. Este valor no podrá ser modificado durante la ejecución del programa. La declaración de constantes es similar s imilar a la de una variable, anteponiendo la palabra reservada const . Por ejemplo: const double PI = 3.1416; const int DIAS_SEMANA = 7; const char letra_inicial = 'F';
Operadores C++ EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
11
Operadores aritméticos. +
Suma
-
Resta
*
Multiplicación
/
División
%
Módulo ó resto de la división entera
En C++ no hay operador de potenciación. Esta operación se realiza con la función pow . El operador % obtiene el resto de la división entre enteros. Requiere que los operandos sean enteros y el segundo operando no sea nulo. Cuando se aplica el operador % a operandos de distinto signo, la mayoría de las versiones de C++ asignan al resultado el signo del primer operando. El operador / requiere que el segundo operando no sea nulo. Si los dos operandos son enteros se obtiene como resultado la parte entera (cociente truncado, sin decimales). Ejemplo de operaciones: int a = 10, b = 3; double v1 = 12.5, v2 = 2.0; char c1='P', c2='T'; //Según la tabla ASCII „P‟=80 „T‟=84 „5‟=53
Expresión
Valor
Expresión
Valor
Expresión
Valor
a+b
13
v1+v2
14.5 c1
80
a-b
7
v1-v2
10.5 c1 + c2
164
a*b
30
v1*v2
25.0 c1 + c2 + 5
169
a/b
3
v1/v2
6.25 c1 + c2 + „5‟
217
a%b
1
En aquellas expresiones en las que aparecen operandos de distinto tipo, C++ convierte los valores al tipo de dato de mayor precisión de todos los datos que intervienen. Esta conversión es de forma temporal, solamente para realizar la operación. Los tipos de datos originales permanecen igual después de la operación. Por ejemplo: int n = 10; double v1 = 12.5, v2; v2 = n + v1; // da como resultado 22.5 para realizar esta operación se convierte el valor de n a tipo double que es el tipo de v1. Realmente n no se modifica, solo su valor es convertido para realizar la suma. Más ejemplos: int i = 7; double f = 5.5; char c = 'w'; // ASCII „w‟=119 „0‟=48
Expresión
Valor
Tipo
i+f
12.5
double
i+c
126
int
i + c – „0‟
78
int
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
12
(i + c) – (2 * f / 5)
123.8
double
En ocasiones resulta útil convertir el valor de una expresión a un tipo de datos diferente: esto se conoce como casting o conversión de tipos que veremos más adelante. En las expresiones en las que aparecen varios operadores aritméticos, el orden de ejecución es siempre de mayor a menor prioridad y dentro de la misma prioridad de izquierda a derecha. Los operadores *, / y % tienen entre ellos la misma prioridad, siendo mayor que la de + y – , que también tienen entre ellos la misma prioridad. (Ver tabla al final de la entrada)
Operadores unitarios. +
–
++
--
signos negativo y positivo incremento y decremento
~ ó compl
Complemento a 1
Estos operadores afectan a un solo operando. El operador incremento ++ incrementa en 1 el valor de la variable. Ejemplo: int i = 1; i++; // Esta instrucción incrementa en 1 la variable i. // Es lo mismo que hacer i = i + 1; i toma el valor 2 El operador decremento – - decrementa en 1 el valor de la variable. Ejemplo: int i = 1; i--; // decrementa en 1 la variable i. // Es lo mismo que hacer i = i - 1; i toma el valor 0 Los operadores incremento y decremento pueden utilizarse como prefijo o sufijo, es decir, pueden aparecer antes o después de la variable. Por ejemplo: i = 5; i++; // i vale ahora 6 ++i; // i vale ahora 7 Cuando estos operadores intervienen en una expresión, si preceden al operando (++i), el valor se modificará antes de que se evalúe la expresión a la que pertenece. En cambio, si el operador sigue al operando (i++), entonces el valor del operando se modificará después de evaluar la expresión a la que pertenece. Por ejemplo: int x, i = 3; x = i++; En esta asignación a x se le asigna el valor 3 y a continuación i se incrementa, por lo tanto, después de ejecutarla: x contiene 3, i contiene 4. Si las instrucciones son: int x, i = 3; x = ++i; En esta instrucción primero se incrementa i y el resultado se asigna a x. Por lo tanto, después de ejecutarla: x contiene 4, i contiene 4. Otro ejemplo: int i = 1;
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
13
cout << i << “ “; cout << ++i << “ “; cout << i << “ “;
Estas instrucciones mostrarán por pantalla: 122 En cambio, si se cambia la posición del operador: int i = 1; cout << i << endl; cout << i++ << endl; cout << i << endl; Estas instrucciones mostrarán por pantalla: 1 1 2 El operador complemento a 1 ~ cambia de valor todos los bits del operando (cambia unos por ceros y ceros por unos). Solo puede usarse con datos de tipo entero. Puede usarse el carácter ~ (ASCII 126) ó el operador equivalente compl. Por ejemplo: int a = 1, b = 0, c = 0; c = ~a; b = compl a;
Operadores relacionales y lógicos. Los operadores relacionales comparan dos operandos y dan como resultado de la comparación verdadero ó falso. Los operadores relacionales en C++ son: <
Menor que
>
Mayor que
<=
Menor o igual
>=
Mayor o igual
!= ó not_eq
Distinto
==
Igual
Los operadores lógicos se utilizan con operandos de tipo lógico y dan como resultado verdadero o falso. Los operadores lógicos en C++ son: && ó and El resultado es verdadero si los dos operandos son verdaderos. El resultado el falso en caso contrario. Si el primer operando es falso no se evalúa el segundo, ya que el resultado será falso. || ó or El resultado es falso si los dos operandos son falsos. Si uno es verdadero el resultado es verdadero. Si el primer operando es verdadero no se evalúa el segundo. ! ó not Se aplica sobre un solo operando. Cambia el valor del operando de verdadero a falso y viceversa. Los operadores relacionales se utilizan para construir expresiones lógicas, cuyo resultado es de tipo cierto o falso. En C++ toda expresión numérica con un valor distinto de cero (no sólo el 1) se considera como cierta y el valor cero como falsa. EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
14
Por ejemplo, en la siguiente tabla vemos una serie de expresiones lógicas y su valor: int i = 7; float f = 5.5F; char c = „w‟;
Expresión
Resultado
(i >= 6) && (c == „w‟)
Cierto
(i >= 6) || (c == 119)
Cierto
(f < 11) and (i > 100)
Falso
(c != „p‟) or ((i + f) <= 10)
i + f <= 10
Cierto Falso
i >= 6 && c == „w‟
Cierto
c != „p‟ || i + f <= 10
Cierto
Las expresiones lógicas compuestas que constan de expresiones lógicas individuales unidas por los operadores lógicos && y || se evalúan sólo hasta que se ha establecido el valor cierto o falso del conjunto. Cuando, por ejemplo, una expresión va a ser seguro falsa por el valor que ha tomado uno de sus operandos, C++ ya no evalúa el resto de expresión.
Operadores a nivel de bits Operan con datos de tipo entero. Realizan con sus operandos las operaciones lógicas and, or, xor y desplazamiento bit a bit. Los operadores a nivel de bits en C++ son: & ó bitand and a nivel de bits | ó bitor
or a nivel de bits
^ ó xor
xor a nivel de bits
<< desplazamiento a la izquierda, rellenando con ceros a la derecha >> desplazamiento a la derecha, rellenando con el bit de signo por la izquierda Por ejemplo: int a = 11, b = 7, c; c = a & b; // 11 & 7, en binario: 1011 and 0111 = 0011 que es el 3 en decimal cout << c << endl; // muestra 3 c = a | b; cout << c << endl; // muestra 15 c = a ^ b; cout << c << endl; // muestra 12 c = b << 1; cout << c << endl; // muestra 14. Equivale a b * 2 c = b >> 1; cout << c << endl; // muestra 3. Equivale a 3 / 2
Operadores de asignación. Se utilizan para asignar el valor de una expresión a una variable. =
Asignación
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
15
+=
Suma y asignación
– =
Resta y asignación
*=
Producto y asignación
/=
División y asignación
%=
Resto de la división entera y asignación
<<=
Desplazamiento a la izquierda y asignación
>>=
Desplazamiento a la derecha y asignación
&= ó and_eq
and sobre bits y asignación
|= ó or_eq
or sobre bits y asignación
^= ó xor_eq
xor sobre bits y asignación
Si los dos operandos de una expresión de asignación son de distinto tipo, el valor de la expresión de la derecha se convertirá al tipo del operando de la izquierda. Por ejemplo, una expresión de tipo real (float, double) se truncará si se asigna a un entero, o una expresión de tipo double se redondeará si se asigna a una variable de tipo float. En C++ están permitidas las asignaciones múltiples. Ejemplo: a = b = c = 3; equivale a a = 3; b = 3; c = 3; Ejemplo de asignaciones: a += 3; equivale a a = a + 3; a *= 3; equivale a a = a * 3; En general: variable op= expresión equivale a: variable = variable op expresión En la siguiente tabla vemos más ejemplos de asignaciones: int i = 5, j = 7, x = 2, y = 2, z = 2; float f = 5.5F, g = -3.25F; Expresión
Expresión equivalente
Valor final
i += 5
i=i+5
10
f – = g
f = f – g
8.75
j *= (i – 3)
j = j * (i – 3)
14
f /= 3
f=f/3
1.833333
i %= (j - 2)
i = i % (j – 2)
0
x *= -2 * (y + z) / 3
x = x * (-2 * (y + z) / 3)
-4
Operador condicional. Lo forman los caracteres ? y : Se utiliza de la forma siguiente: expresión1 ? expresión2 : expresión3 Si expresión1 es cierta entonces se evalúa expresión2 y éste será el valor de la expresión condicional. Si expresión1 falsa, se evalúa expresión3 y éste será el valor de la expresión condicional. Por ejemplo: int i = 10, j; j = (i < 0) ? 0 : 100;
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
16
Esta expresión asigna a j el valor 100. Su significado es: si el valor de i es menor que 0 asigna a j el valor 0, sino asigna a j el valor 100. Como i vale 10, a j se le asigna 100. La instrucción anterior es equivalente a escribir: if(i < 0) j = 0; else j = 100; Más Ejemplos de operador condicional en C++: int a=1, b=2, c=3; c+=(a>0 && a<= 10) ? ++a : a/b; /* c toma el valor 5*/ int a=50, b=10, c=20; c+=(a>0 && a<=10) ? ++a : a/b; /* c toma el valor 25*/
Otros operadores Operador coma La coma, usada como operador, se utiliza para encadenar varias expresiones. Ejemplo:
x=(v=3,v+5)
Equivale a:
v=3 x=v+5
Ejemplo:
z=26 v=(z=z+10,72/z)
Equivale a:
z=26 z=z+10 v=72/z
Operador de dirección Se representa por el símbolo & (ampersand), y su función es la de obtener la dirección dónde se almacena una determinada variable. Por ejemplo, dadas las siguientes instrucciones: int x = 10; cout << “Valor de x: “ << x << endl; cout << “Dirección de la variable x: “ << &x << endl;
muestran por pantalla: Valor de x: 10 Dirección de la variable x: 0x27ff44
Operador de indirección Se representa por un asterisco *, y su función es la de obtener el valor contenido en una dirección de memoria.
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
17
Un puntero es una variable que contiene una dirección de memoria. Para definir una variable puntero se escribe: tipo *variable. Por ejemplo: int *p; En el siguiente ejemplo se declara un puntero y dos variables enteras y se utiliza el operador de indirección para obtener el valor contenido en una dirección de memoria. int *p, x = 10, y = 0; //se declara el puntero p y las variable x e y p = &x; //a p se le asigna la dirección de memoria de x y = *p; //a y se le asigna el valor guardado en la dirección de memoria que contiene p. Como p contiene la dirección de x, a y se le asigna el valor 10 Veremos los punteros en un tema posterior.
Operador referencia a Una referencia es un nombre alternativo (un alias, un sinónimo) para un objeto. La forma general de expresar una referencia es: tipo &referencia = variable; Por ejemplo: float m = 30.01; float &n = m; // n es una referencia de m Se ha declarado la variable m como float y n como referencia de m, indicando al compilador que en este programa m también tiene otro nombre ( n ). Las operaciones realizadas sobre m se reflejan en n, y viceversa. Por lo tanto en el programa podemos utilizar indistintamente m o n.
Una referencia no es una copia de la variable referenciada, sino que es la misma variable con un nombre diferente. Los operadores no operan con la referencia sino directamente sobre la variable referenciada. Por ejemplo: int j = 0; int &k = j; // k es una referencia a j; k++; cout << j << endl; // muestra 1 cout << k << endl; // muestra 1; Una referencia debe ser inicializada y su valor no puede ser alterado después de haberla inicializado, por lo que siempre se referirá al mismo objeto. Las referencias se utilizan, por ejemplo, como alternativa a los punteros en el paso de parámetros en las funciones.
Operador global y de resolución de ámbito Es el operador :: y permite el acceso a una variable global que ha quedado oculta por una variable local. En POO se usa para indicar a qué clase pertenece un determinado método.
Operador sizeof Obtiene el tamaño en bytes de un tipo de datos o de una variable previamente declarada. Por Ejemplo, las siguientes instrucciones: double a; cout << “Entero-> “ << sizeof(int) << endl; cout << “Caracter-> “ << sizeof(char) << endl;
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
18
cout << “Double-> “ << sizeof(a) << endl;
Dan como resultado: Entero-> 4 Caracter-> 1; Double-> 8 El operador sizeof se puede utilizar con tipos primitivos y con tipos derivados.
Prioridad y orden de evaluación de los operadores en C++ La siguiente tabla muestra todos los operadores de C++ ordenados de mayor a menor prioridad. Los operadores que aparecen en la misma línea tienen la misma prioridad. :: () [] . -> n++ n-- _cast typeid signo ~ ! * & ++n - – n sizeof new delete (tipo) ->* .* * / % + << >> < <= > >= == != & ^ | && || ?: = += -= *= /= %= <<= >>= &= |= ^= ,
Sin asociatividad Izquierda a Derecha Derecha a Izquierda Izquierda a Derecha Izquierda a Derecha Izquierda a Derecha Izquierda a Derecha Izquierda a Derecha Izquierda a Derecha Izquierda a Derecha Izquierda a Derecha Izquierda a Derecha Izquierda a Derecha Izquierda a Derecha Derecha a Izquierda Derecha a Izquierda Izquierda a Derecha
Casting. Conversión entre tipos de datos en C++ Cuando en una expresión en C++ intervienen operandos de distinto tipo, los datos se convierten de forma temporal al operando de mayor precisión para realizar la operación. Cuando a un variable se le asigna un valor que no es de su tipo, C++ convierte el valor de la derecha al tipo de la variable a la que se le va a asignar siempre que no haya pérdida de información. Si se produce pérdida de información el compilador avisará de ello. En una asignación de tipos distintos puede ocurrir que: 1. Un valor real (tipo double o float) puede truncarse (pierde la parte decimal) si se asigna a una variable entera. 2. Un valor de tipo double puede ser redondeado si se asigna a una variable de tipo float. 3. Un valor de tipo entero puede ser modificado si se asigna a una variable entera de menor precisión o a una variable de tipo char. Algunos de los bits más significativos pueden perderse.
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
19
Por ejemplo, dadas las siguientes declaraciones de variables: long int k; unsigned char m; double p; int n, q; Para calcular la siguiente expresión: q = k + m * n / p el proceso es el siguiente: 1. Se realiza la multiplicación m * n. Para ello se convierte m (unsigned char) a int y a continuación se multiplica por n. El resultado es de tipo int. 2. Se realiza la división. Como p es de tipo double, el resultado anterior de multiplicar m * n que es de tipo int se convierte a double y se hace la división. El resultado es de tipo double. 3. Se realiza la suma. Para ello se convierte k (long) a double y se suma al resultado de la división anterior. El resultado de la suma es de tipo double. 4. El último paso es asignar el resultado de tipo double a q que es de tipo int. En este caso el resultado se pasa a tipo int por truncamiento, o sea, eliminando la parte fraccionaria. En este caso de pérdida de precisión el compilador avisará de ello. Estas conversiones las realiza C++ de forma automática. Esta conversión se conoce como conversión implícita. En algunos casos necesitaremos asignar datos de un tipo a variables que son de otro tipo y que el compilador no nos avise ello y permita realizar la operación. En ese caso utilizaremos la conversión explícita o casting. En general, el uso del casting es obligatorio cuando se hacen asignaciones con pérdida de precisión. Un casting lo podemos hacer, siguiendo el modelo de C, de dos formas: (tipo) expresión ó tipo(expresión) Por ejemplo: float a = 10.2; int b, c = 5; b = (int)(a + c); // convierte a int por truncamiento. Asigna a b el valor 15 c = int (a); // asigna a c el valor 10 Si en las instrucciones anteriores no realizamos el casting el compilador avisará de la pérdida de precisión y no nos dejará hacerlo. Otro ejemplo. Dadas las variables: int i = 7; float f = 8.5; La expresión (i + f) % 4 no es válida, ya que (i + f) produce un resultado en coma flotante. Esto se puede solucionar con un casting: ((int) (i + f)) % 4. Sea ahora la expresión ((int) f) % 3, es una expresión válida, que da como resultado el valor 2, pero debemos tener en cuenta que lo que se convierte en entero es el valor de f, y sólo para esta expresión, ya que después f sigue teniendo el valor 8.5. Un casting también puede ser considerado como un operador unitario. Además de esta forma de realizar un casting que es la tradicional de C, C++ incorpora 4 nuevos operadores para realizar un casting de forma explícita:
static_cast
(expresión) Convierte el tipo de la expresión al tipo indicado. EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
20
Se utiliza para realizar conversiones entre tipos relacionados, por ejemplo entre un float y un int.
const_cast(expresión) Convierte el tipo de la expresión al tipo indicado. Se utiliza para eliminar la acción del calificador const sobre la expresión.
dynamic_cast(expresión) Convierte el tipo de la expresión al tipo indicado. Se utiliza para realizar conversiones verificadas durante la ejecución, examinando el tipo del objeto que convierte. Si la conversión es entre punteros y durante la ejecución no se puede realizar, devuelve un cero (puntero nulo).
reinterpret_cast(expresión) Convierte el tipo de la expresión al tipo indicado. Se utiliza para realizar conversiones entre tipos no relacionados, por ejemplo, conversiones double * a int * que static_cast no permite. Por ejemplo: float a = 10.2F; int b, c = 5; b = static_cast(a + c); // Asigna a b el valor 15 c = static_cast(a);
// asigna a c el valor 10
Estructura de un programa C++ C++ es un lenguaje de programación orientado a objetos híbrido. Esto quiere decir que permite realizar programas estructurados sin la orientación a objetos y programas orientados a objetos. En este punto veremos la estructura de un programa que no utiliza orientación a objetos. En temas posteriores estudiaremos la estructura de un programa C++ orientado a objetos. La estructura general de un programa C++ es la siguiente: Comentarios Directivas del preprocesador Declaración de variables globales y funciones int main( ) // Función principal main { Declaraciones locales de la función principal Instrucciones de la función principal } Otras funciones: funcion1(.....) { Declaraciones locales de la función 1 Instrucciones de la función 1 } funcion2(.....) { Declaraciones locales de la función 2 Instrucciones de la función 2 }
..... Por ejemplo:
// Programa que muestra el mensaje Hola mundo!!! por pantalla #include
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
21
using namespace std; int main(void) { cout << "Hola mundo!!!\n"; } Vamos a comentar cada una de las partes del programa anterior:
// Programa que muestra el mensaje Hola mundo!!! por pantalla Esta línea es un comentario. Todas las líneas que comienzan con dos barras (//) se consideran comentarios y no tienen ningún efecto sobre el comportamiento del programa. Los comentarios también pueden ir entre los símbolos /* y */. En ese caso pueden ocupar más de una línea.
#include Esta línea es una directiva del preprocesador . Todas las líneas que comienzan con el símbolo # son directivas para el preprocesador. La directiva #include, sirve para insertar ficheros externos dentro de nuestro programa. Estos ficheros son conocidos como ficheros incluidos, ficheros de cabecera o headers. En este caso, la directiva #include indica al preprocesador que en este programa se debe incluir el archivo iostream. El código fuente no cambia, pero el compilador ve el fichero incluido. iostream es la librería de entrada/salida de C++. Si no se incluye esta librería no podemos utilizar la instrucción cout para imprimir un mensaje por pantalla. La inclusión de ficheros la podemos realizar de dos formas: #include #include "nombre de fichero de cabecera" En el primer caso el preprocesador buscará en los directorios include definidos en el compilador. En el segundo, se buscará primero en el directorio actual, es decir, en el que se encuentre el fichero fuente, si no existe en ese directorio, se buscará en los directorios include definidos en el compilador. Si se proporciona el camino como parte del nombre de fichero, sólo se buscará en el directorio especificado.
using namespace std; En grandes proyectos formados por varios archivos, es posible que en archivos diferentes del mismo proyecto se encuentren recursos con el mismo nombre. Para evitar confusiones y saber a qué recurso estamos haciendo referencia se utilizan los espacios de nombres (namespace). Un espacio de nombres es básicamente un conjunto de nombres de recursos (clases, métodos, funciones, etc) en el cual todos los nombres son únicos. Todos los elementos de la biblioteca estándar de C++ se declaran dentro de un espacio de nombres llamado std. Con la instrucción using namespace std estamos indicando que vamos a usar este espacio de nombres. Esta línea se incluirá en la mayoría de programas que escribamos en C++. Si no la escribimos, la instrucción cout << "Hola mundo!!!\n"; tendríamos que escribirla indicando el espacio de nombres donde se declara cout así: std::cout<<”Hola mundo!!!\n”;
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
22
int main (void) Un programa en C++ no orientado a objetos está formado básicamente por una o varias funciones. La función main es la función principal del programa. La función principal es el punto de inicio del programa. Si el programa contiene varias funciones, la ejecución del mismo comienza por la función main. Todo programa escrito en C++ debe contener una función main. Las llaves { } indican donde empiezan y donde acaban las instrucciones de la cout << "Hola mundo!!!\n";
función.
Esta línea muestra por pantalla Hola mundo!!! y un salto de línea. cout es un objeto que se declara en el archivo iostream en el espacio de nombres std, por eso tenemos que incluir ese archivo al principio del programa y declarar que vamos a utilizar ese espacio de nombres. La instrucción acaba con punto y coma. El punto y coma se utiliza para indicar el final de una instrucción y sirve para separarla de instrucciones posteriores.
Salida con formato en C++. Manipuladores Para dar formato a los datos que se muestran por pantalla, C++ asocia con el stream de salida un conjunto de manipuladores que permiten modificar la forma en la que son visualizados los resultados. Un manipulador equivale a una llamada a una función. Algunos de los manipuladores más comunes son los siguientes: dec conversión a decimal hex conversión a hexadecimal oct conversión a octal skipws extrae un espacio en blanco inicial endl se imprime un „\n‟ y se vacía el buffer de salida flush se vacía el buffer de salida setw(int w) establece la anchura mínima de campo setprecision(int p) establece el número de cifras significativas, por defecto 6. setfill(char ch) establece el carácter de relleno left la salida se alinea a la izquierda rigth la salida se alinea a la derecha internal se alinea el signo y los caracteres indicativos de la base por la izquierda y las cifras por la derecha showbase se muestra la base de los valores numéricos showpoint se muestra el punto decimal uppercase los caracteres de formato aparecen en mayúsculas showpos se muestra el signo (+) en los valores positivos scientific notación científica para coma flotante fixed notación normal de C++ para coma flotante setiosflag(long i) establece una lista de flags de formato resetriosflag(long i) suprime una lista de flags de formato Los manipuladores pueden tener argumentos o no tenerlos. Los manipuladores sin argumentos (endl, flush, etc.) están definidos en iostream. Los que tienen argumentos están declarados en iomanip. Un manipulador sólo afecta al stream (cin, cout, etc.) al que se aplica. Un manipulador en C++ se utiliza de la forma: cout << hex << 100; cout << setw(10) << “Hola” << endl;
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
23
El efecto de los manipuladores permanece en el stream correspondiente hasta que se cambian por otro manipulador, a excepción de setw(n) que hay que introducirlo en el flujo antes de cada dato al que se le quiere aplicar ese ancho de campo. Ejemplo: //********************************************************* // Ejemplo de uso de manipuladores setfill y setw //********************************************************* #include #include // define diferentes manipuladores using namespace std; int main(void) { cout << setfill('.'); // manipulador de relleno. //el carácter de relleno será el punto cout << "Listado de calificaciones\n" << endl; cout << "Roberto Aniorte" << setw(20) << "8.5" << endl; cout << "Andrea Gutierrez" << setw(19) << "6.9" << endl; cout << "Isabel Sanchez" << setw(21) << "5.7" << endl; cout << "Anastasio Castro" cout << "Barbara Lopez" << cout << "Martin Garcia" << cout << setfill('\0'); // cout << endl; system("pause");
<< setw(19) << "7.5" << endl; setw(22) << "7.8" << endl; setw(22) << "9.1" << endl; se restablece el carácter de relleno
}
Este programa muestra:
Otro ejemplo de uso de manipuladores: //Ejemplo de uso de manipuladores #include #include using namespace std; int main(void) { double a1 = 101.179; double a2 = 3.12; cout << "a1->" << a1 << endl; cout << "a2->" << a2 << endl; cout << endl; cout << fixed << "a1->" << a1 << endl; cout << "a2->" << a2 << endl; cout << endl; cout << "a1->" << setprecision(1) << a1 << endl; cout << "a2->" << a2 << endl; cout << endl;
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
24
cout << "a1->" << setw(10) << setfill('.') << a1 << endl; cout << "a2->" << a2 << endl; cout << "a1->" << setw(12) << a1 << endl; system("pause"); }
Este programa muestra como salida:
Otro ejemplo de uso de manipuladores: // programa que lee un radio y calcula // la longitud de la circunferencia // el área del círculo // y el volumen de la esfera correspondiente a ese radio #include #include #include using namespace std; int main(void) { const double PI = 3.1416; double radio; cout << "Introduce el valor del radio : "; cin >> radio; cout << fixed << setprecision(2); // notación en coma flotante // con 2 decimales cout << endl << "Longitud de la circunferencia: " << 2*PI*radio; cout << endl << "Area del circulo: " << PI*pow(radio,2); cout << endl << "Volumen de la esfera: "; cout << (4.0/3)*PI*pow(radio,3) << endl; system("pause"); }
Este programa muestra como salida:
Leer caracteres y cadenas de caracteres en C++
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
25
Método get() para leer un carácter Para leer por teclado datos que están separados por espacios en blanco o intro se puede usar el operador de extracción >> sobre cin. Pero si queremos leer caracteres incluidos espacios en blanco o el intro este operador no nos sirve.En ese caso podemos utilizar el método get. La forma de uso es: cin.get(caracter); El método get extrae de cin un carácter y lo guarda en la variable. Si el carácter extraído es el de fin de fichero se activa el indicador de fin de fichero. Si el buffer de entrada está vacío, cuando llega a esta instrucción el programa se detiene esperando que se teclee un carácter y se pulse intro. Por ejemplo, el siguiente programa lee un carácter por teclado y muestra su código ASCII. #include using namespace std; int main(void) { char c; cout << "Introduce un caracter: "; cin.get(c); cout << "ASCII de " << c << " -> " << static_cast(c) << endl; system("pause"); }
El método get extrae del flujo caracteres incluso el intro. En algunas ocasiones leer el intro que puede tener efectos no deseados. En el siguiente programa vemos un ejemplo en el que el carácter intro que queda en el buffer después de introducir un entero hace que el programa no funcione como esperamos. Este programa lee un número entero y muestra si es par o impar y a continuación lee un carácter y muestra si es una letra minúscula: #include using namespace std; int main(void) { char c; int num; //leemos un número entero cout << "Introduce un numero entero: "; cin >> num; cout << "El numero es " << ((num%2==0)? "par" : "impar") << endl; //leemos un carácter cout << "Introduce un caracter: "; cin.get(c); cout << "El caracter" << ((c>='a' and c<='z')?" es ":" no es"); cout << " una letra minuscula" << endl; system("pause"); }
la ejecución de este programa es la siguiente:
Tras el mensaje “Introduce un carácter” el programa no espera a que se teclee y muestra directamente el mensaje “El carácter no es una letra minúscula”. Esto ocurre porque cuando se ha introducido el valor 18
realmente en el flujo de entrada está ese valor más el intro que hemos pulsado:
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
26
Flujo de entrada cin: 18\n Mediante la instrucción cin >> num; se le asigna a num el valor 18. Este valor se extrae de cin pero el \n permanece: Flujo de entrada después de leer el entero: \n Cuando el programa llega a la instrucción cin.get(c); extrae de cin el intro y se lo asigna a c. No se detiene la ejecución del programa para que se introduzca el carácter y se produce un resultado no deseado. Para evitar esto, en estos casos es necesario limpiar el buffer con el método ignore . El programa modificado, limpiando el intro para que funcione correctamente es: #include using namespace std; int main(void) { char c; int num; //leemos un número entero cout << "Introduce un numero entero: "; cin >> num; cout << "El numero es " << ((num%2==0)? "par" : "impar") << endl; //limpiamos el buffer de entrada
cin.ignore(numeric_limits::max(),'\n'); //leemos un carácter cout << "Introduce un caracter: "; cin.get(c); cout << "El caracter" << ((c>='a' and c<='z')? " es ":" no es"); cout << " una letra minuscula" << endl; system("pause"); }
Método getline() para leer una cadena de caracteres El operador >> sobre cin no es útil para leer cadenas de caracteres que contengan espacios en blanco. Por ejemplo, para leer en un programa el nombre y apellidos de una persona, si utilizamos las siguientes instrucciones: char nombre[50]; // cadena de caracteres de longitud máxima 50 ... cout << "Introduce tu nombre: "; cin >> nombre ...
Si tecleamos Lucas Alonso Guzman, a la variable nombre solo se le asignará Lucas ya que a continuación se encuentra un espacio en blanco y el operador >> entiende que es el final de la asignación. Para evitar esto se utiliza el método getline. La forma general de uso es: cin.getline(cadena, num, carácter_final); getline lee una serie de caracteres desde el flujo de entrada y los almacena en la variable cadena. Se leen caracteres hasta el final del flujo, hasta el primer carácter que coincide con el carácter_final especificado, el cual se desecha ó hasta que se han leído num-1 caracteres; en este último caso el estado del flujo pasa a ser de fallo. Esto se puede comprobar con el método fail(). El estado de fallo se produce porque se han leído num-1 caracteres que es el máximo que queremos leer y aun han quedado caracteres en el flujo por lo que es posible que se hayan tecleado más caracteres de la cuenta y pueden provocar un error en la siguiente lectura. getline añade automáticamente el carácter nulo (\0) al final de la cadena extraída.
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
27
Utilizando getline para leer nombre y apellidos del ejemplo anterior escribiremos: cin.getline(nombre, 50, '\n'); El carácter final se puede omitir, si no aparece se supone que es \n : cin.getline(nombre, 50);
Ejemplos de lectura de caracteres en C++ Ejemplo 1: El siguiente ejemplo muestra la diferencia cuando se leen cadenas de caracteres en C++ usando o no getline: #include using namespace std; int main(void) { char nombre[40]; cout << "Introduce nombre y apellidos: "; cin.getline(nombre,40); //lectura incluyendo espacios cout << "Hola " << nombre << endl; cout << "Introduce nombre y apellidos: "; cin >> nombre; //lectura sin incluir espacios cout << "Hola " << nombre << endl; system("pause"); }
La salida de este programa es:
Ejemplo 2: En el siguiente ejemplo se leen cadenas de caracteres hasta que se pulsa F6. Se comprueba y se muestra el estado del flujo cin después de cada lectura. #include using namespace std; int main(void) { char cadena[15]; cout << "Introduzca cadena de caracteres. F6 Para finalizar\n\n"; do { cout << "cadena: "; cin.getline(cadena,15,'\n'); //se muestran los bits de estado del flujo cin para //comprobar el resultado de la lectura cout << "bit eof->" << cin.eof() << " "; cout << " bit fail->" << cin.fail() << endl; //si la cadena excede de 15 cin.fail() toma el valor 1 //si no se ha pulsado F6 en el nombre (fin de lectura) //y el nombre excede de la longitud máxima permitida //se eliminan el resto de los caracteres if(!cin.eof() && cin.fail()) { cin.clear(); cin.ignore(numeric_limits::max(),'\n');
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
28
} }while(!cin.eof()); system("pause"); }
La salida de este programa es la siguiente:
Limpiar el Buffer del Teclado Para limpiar el buffer de entrada estándar con el método cin.ignore() el cual por defecto borra el primer caracter que encuentra en el buffer (normalmente „\n‟). Otra forma, es pasando al mismo método dos parámetros, que son la cantidad de caracteres que serán borrados (máximo 256), y el caracter en el cual terminará el borrado, para nuestro caso „\n‟. cin.ignore(256,’ \n ’);
Sentencias de iteración – Ciclos repetitivos Definición Las Sentencias de Iteración o Ciclos son estructuras de control que repiten la ejecución de un grupo de instrucciones. Básicamente, una sentencia de iteración es una estructura de control condicional, ya que dentro de la misma se repite la ejecución de una o más instrucciones mientras o hasta que una a condición específica se cumpla. Muchas veces tenemos que repetir un número definido o indefinido de veces un grupo de instrucciones por lo que en estos casos utilizamos este tipo de sentencias. En C++ los ciclos o bucles se construyen por medio de las sentencias for , while y do - while. La sentencia for es útil para los casos en donde se conoce de antemano el número de veces que una o más sentencias han de repetirse. Por otro lado, la sentencia while es útil en aquellos casos en donde no se conoce de antemano el número de veces que una o más sentencias se tienen que repetir.
Sentencia For for(contador; final; incremento) { Código a Repetir; }
donde: 1. contador es una variable numérica 2. final es la condición que se evalúa, o sea, el valor final para contador 3. incremento es el valor que se suma o resta al contador Ejemplo 1: EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
29
#include Using namespace std; int main(int argc, char* argv[]) { for(int i=1; i<=10; i++) { cout<<"Hola Mundo"<
return 0; }
Esto indica que el contador "i" inicia desde 1 y finaliza cuando el contador "i" sea menor o igual a 10 ( en este caso llegará hasta 10) e "i++" realiza la sumatoria por unidad lo que hace que el for y el contador se sumen. repitiendo 10 veces "HOLA MUNDO" en pantalla. Ejemplo 2: #include Using namespace std; int main() { for(i=10; i>=0; i--) { cout<<"Hola Mundo"<
return 0; }
Este ejemplo hace lo mismo que el primero, salvo que el contador se inicializa a 10 en lugar de 1; y por ello cambia la condición que se evalúa así como que el contador se decremento en lugar de ser incrementado .
Sentencia while while(condición) { código a Repetir }
donde: 1. condición es la expresión a evaluar Ejemplo 1: #include Using namespace std; int main(int argc, char* argv[]) { int contador = 0; while(contador<=10) { contador=contador++;
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
30
cout<<"Hola Mundo"<
return 0; }
El contador Indica que hasta que este llegue a el total de 10 entonces se detendrá y ya no se realizará el código contenido dentro de la sentencia while, de lo contrario mientras el "contador" sea menor a 10 entonces el código contenido se ejecutará desplegando hasta 10 veces "Hola Mundo" en pantalla.
Sentencia do - while La sentencia do es usada generalmente en cooperación con while para garantizar que una o más instrucciones se ejecuten al menos una vez. Por ejemplo, en la siguiente construcción no se ejecuta nada dentro del ciclo while, el hecho es que el contador inicialmente vale cero y la condición para que se ejecute lo que está dentro del while es "mientras el contador sea mayor que diez". Es evidente que a la primera evaluación hecha por while la condición deja de cumplirse. int contador = 0; while(contador > 10) { contador ++; cout<<"Hola Mundo"; }
Al modificar el segmento de código anterior usando do tenemos: #include Using namespace std; int main(int argc, char* argv[]) { int contador = 0; do { contador ++; cout<<"Hola Mundo"; } while(contador > 10); system(“pause”);
return 0; }
Observe cómo en el caso de do la condición es evaluada al final en lugar de al principio del bloque de instrucciones y, por lo tanto, el código que le sigue al do se ejecuta al menos la primera vez.
Generar Números Aleatorios en C++ Para generar números aleatorios en C++ se utilizan las funciones rand y srand.
Función rand() La función rand calcula un número aleatorio en el intervalo entre 0 y RAND_MAX. El valor de RAND_MAX es una constante predefinida que representa el mayor valor que puede devolver la función rand. En Dev-C++ este valor es 32767.
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
31
Ejemplo: Programa C++ que genera 20 números aleatorios. #include using namespace std; int main() { int i; cout << "20 numeros generados aleatoriamente:\n"; for(i=1; i<=20; i++) cout << rand() << endl; system("pause"); }
La función rand genera números a partir de un valor inicial o semilla. Si ejecutamos el programa anterior varias veces seguidas obtendremos siempre la misma secuencia de números. Para que esto no se produzca debemos cambiar el valor inicial de la semilla cada vez que se ejecute el programa. Esto se hace con la función srand.
Función srand() La función srand fija el punto de comienzo para generar números aleatorios. El generador de números aleatorios obtiene los números en función del valor de su argumento. Cuando esta función no se utiliza, el valor del primer número generado siempre es el mismo para cada ejecución (corresponde a un argumento de valor 1). Para obtener números aleatorios mediante estas funciones, es recomendable utilizar como semilla un valor que cambie constantemente, como por ejemplo, el valor devuelto por la función time (librería ctime). Esta función devuelve el número de segundos transcurridos desde las 0 horas del 1 de Enero de 1970. Podemos comprobar el funcionamiento modificando el ejemplo anterior para que genere números diferentes en cada ejecución: #include
#include using namespace std; int main() {
srand(time(NULL)); int i; cout << "20 numeros generados aleatoriamente:\n"; for(i=1; i<=20; i++) cout << rand() << endl; system("pause"); }
Para generar números aleatorios entre dos límites DESDE – HASTA utilizaremos la siguiente expresión: numero = aleatorio = rand()%(HASTA-DESDE+1)+DESDE;
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
32
Ejemplo: Programa C++ que genera números aleatorios entre 4 y 10. La cantidad de números a generar se pide por teclado #include #include using namespace std; int main() { srand(time(NULL)); int i, n, aleatorio, DESDE=4, HASTA=10; cout << "Numeros aleatorios entre " << DESDE << " y " << HASTA << endl; cout << "Cuantos numeros aleatorios quiere generar? "; cin >> n; for (i = 1; i <= n; i ++) { aleatorio = rand()%(HASTA-DESDE+1)+DESDE; cout << aleatorio << " "; } cout << endl; system("pause"); }
Otro ejemplo /* srand example */ #include #include /* srand, rand */ #include /* time */ using namespace std; int main () { cout<<"First number: "<< rand()%100<
enum Sintaxis: enum nombre {lista-de-nombres} variable-lista; La palabra clave enum es usada para crear un tipo enumerador llamado nombre que consiste de los elementos en lista-de-nombre. La variable-lista es opcional, y puede ser usada para crear instancias de tipo nombre junto con la declaracion. Por ejemplo, el siguiente código crea un tipo enumerador para colores: enum ColorT {rojo, naranja, amarillo, verde, azul, indigo, violeta}; ... ColotT c1 = indigo; if( c1 == indigo ) {
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
33
cout << "c1 es índigo" << endl; }
En el ejemplo anterior, el efecto de enumeración es introducir nuevas constantes llamadas rojo, naranja, amarillo, etc. Por defecto, estas constantes son asignadas consecutivamente como enteros empezando en cero. Puedes cambiar los valores de estas constantes, como es mostrado en el siguiente ejemplo: int main(int argc, char* argv[]) { enum ColorT { rojo = 10, azul = 166, verde }; //verde toma el valor de azul+1 ColorT c = azul; cout << "c es " << c << endl; system(“pause”);
return 0; }
Se pone typedef para que funcione en compiladores C y C++ a la par: typedef enum ColorT { rojo = 10, azul = 15, verde } ColorT; ColorT c = verde; cout << "c es " << c << endl;
Funciones en C++. Una función está formada por un conjunto de sentencias que realizan una determinada tarea y que podemos invocar mediante un nombre. Un programa C++ está formado por una o más funciones. Utilizando funciones podemos construir programas modulares. Además consiguen que no se repita el mismo código en varias partes del programa: en lugar de escribir el mismo código cuando se necesite, por ejemplo para validar una fecha, se hace una llamada a la función que lo realiza. Todo programa C++ tiene una función llamada main. La función main es el punto de entrada al programa y también el punto de salida.
Los parámetros formales son los datos que recibe la función para operar con ellos. Una función puede recibir cero o más parámetros. Se debe especificar para cada parámetro su tipo. Una función puede devolver un dato a quien la ha llamado. Esto se realiza mediante la instrucción return. El tipo del dato devuelto debe coincidir con el tipo_devuelto que se ha indicado antes del nombre de la función.
Ejemplo de función C++ : función que sume dos números enteros //Función C++ para sumar dos números int sumar(int a, int b) { int c; c = a + b; return c; }
Esta función se llama suma y recibe dos números enteros a y b. La función suma los dos números y guarda el resultado en c. Finalmente devuelve mediante la instrucción return la suma calculada.
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
34
Una función tiene un único punto de inicio, representado por la llave de inicio. La ejecución de una función termina cuando se llega a la llave final o cuando se ejecuta la instrucción return. La instrucción return puede aparecer en cualquier lugar dentro de la función, no tiene que estar necesariamente al final. Con una función se deben realizar tres operaciones: declaración, definición y llamada o invocación . Declaración o prototipo de una función. Declarar una función es el paso previo antes de definir el conjunto de sentencias que la componen. En la declaración o prototipo de la función, indicamos el nombre de la misma, el tipo de valor que devuelve y una lista parámetros separados por comas. La declaración acaba con punto y coma . Por ejemplo, la función suma del punto anterior se declara así: int sumar(int a, int b); En la declaración de una función, no es necesario indicar los identificadores de los parámetros. Solo es obligatorio poner el tipo. Además, los identificadores usados en la declaración y en la definición no es preciso que sean los mismos. Según esto, la función suma la podemos declarar así: int sumar(int, int); Estamos indicando que sumar recibe 2 enteros y devuelve un entero. No es necesario poner el nombre de las variables.
Definición de una función. Definir una función consiste en escribir la cabecera de la misma y a continuación, entre llaves, el cuerpo de la función, es decir, sus instrucciones. La cabecera de la función debe coincidir con la declaración de la función y debe incluir el nombre de los parámetros. La cabecera no acaba en punto y coma. Los parámetros definidos en la cabecera de la función se llaman parámetros formales. Son las variables que reciben los valores de los argumentos en la llamada a la función. El resultado de la función se devuelve a la instrucción que la ha llamado por medio de la sentencia return.
Llamar o invocar a una función. Para que una función se ejecute es necesario llamarla o invocarla desde alguna parte del programa. La llamada a una función está formada por su nombre seguido de una lista de argumentos entre paréntesis y separados por comas (cero o más argumentos) que son los datos que se le envían a la función. Los argumentos que aparecen en la llamada a una función se llaman parámetros actuales, porque son los valores que se pasan a ésta en el momento de la ejecución. Los parámetros actuales y los formales deben coincidir en número, orden y tipo. Si el tipo de un parámetro actual no coincide con su correspondiente parámetro formal, el sistema lo convertirá al tipo de este último, siempre que se trate de tipos compatibles. Si no es posible la conversión, el compilador dará los mensajes de error correspondientes. Si la función devuelve un valor, la llamada a la función puede estar incluida en una expresión que recoja el valor devuelto. Cuando se llama a una función, se crean en memoria las variables que aparecen en la cabecera de la función. Las variables declaradas en la cabecera de una función así como las que se declaran en el interior de la misma son variables locales de la función. Esto significa que solo son accesibles dentro de la función. Aunque tengan el mismo nombre que otras variables que puedan aparecer en otras partes del programa se trata
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
35
de variables distintas. La memoria que ocupan las variables locales de una función se libera cuando acaba la ejecución de la función y dejan de estar accesibles. Cuando se llama a una función, la ejecución del programa pasa a la función y cuando ésta acaba, la ejecución continúa a partir del punto donde se produjo la llamada.
Ejemplos de funciones en C++ / function example #include using namespace std; int subtraction (int a, int b) { int r; r=a-b; return r; } int main () { int x=5, y=3, z; z = subtraction (7,2); cout << "The first result is " << z << '\n'; cout << "The second result is " << subtraction (7,2) << '\n'; cout << "The third result is " << subtraction (x,y) << '\n'; z= 4 + subtraction (x,y); cout << "The fourth result is " << z << '\n'; }
The The 5 The The 6
first result is 5 second result is third result is 2 fourth result is
Paso de parámetros en C++ El paso de parámetros en C++ se puede hacer de dos formas: 1. Paso de parámetros por valor. 2. Paso de parámetros por referencia.
1. Paso de parámetros por valor. Pasar parámetros por valor significa que a la función se le pasa una copia del valor que contiene el parámetro actual. Los valores de los parámetros de la llamada se copian en los parámetros de la cabecera de la función. La función trabaja con una copia de los valores por lo que cualquier modificación en estos valores no afecta al valor de las variables utilizadas en la llamada. Aunque los parámetros actuales (los que aparecen en la llamada a la función) y los parámetros formales (los que aparecen en la cabecera de la función) tengan el mismo nombre son variables distintas que ocupan posiciones distintas de memoria. Por defecto, todos los argumentos salvo los arrays se pasan por valor.
Ejemplo de paso de parámetros por valor El siguiente programa lee un número entero y llama a una función que invierte las cifras del número: #include using namespace std; int invertir (int);
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
36
int main() { int num; int resultado; cout << "Introduce un numero entero: "; cin >> num; resultado = invertir(num); cout << "Numero introducido: " << num << endl; cout << "Numero con las cifras invertidas: " << resultado << endl; system("pause"); } int invertir(int num) { int inverso = 0, cifra; while (num != 0) { cifra = num % 10; inverso = inverso * 10 + cifra; num = num / 10; } return inverso; }
La salida de este programa es:
En la llamada a la función el valor de la variable num se copia en la variable num de la cabecera de la función. Aunque tengan el mismo nombre, se trata de dos variables distintas. Dentro de la función se modifica el valor de num, pero esto no afecta al valor de num en main. Por eso, al mostrar en main el valor de num después de la llamada aparece el valor original que se ha leído por teclado.
2. Paso de parámetros por referencia. El paso de parámetros por referencia permite que la función pueda modificar el valor del parámetro recibido. Vamos a explicar dos formas de pasar los parámetros por referencia: 2.1 Paso de parámetros por referencia basado en punteros al estilo C. 2.2 Paso de parámetros por referencia usando referencias al estilo C++. 2.1 Paso de parámetros por referencia utilizando punteros.
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
37
Cuando se pasan parámetros por referencia, se le envía a la función la dirección de memoria del parámetro actual y no su valor . La función realmente está trabajando con el dato original y cualquier modificación del valor que se realice dentro de la función se estará realizando con el parámetro actual. Para recibir la dirección del parámetro actual, el parámetro formal debe ser un puntero .
Ejemplos de paso de parámetros por referencia Ejemplo 1: Programa c++ que lee dos números por teclado y los envía a una función para que intercambie sus valores. #include using namespace std;
void intercambio(int *, int *); int main( ) { int a, b; cout << "Introduce primer numero: "; cin >> a; cout << "Introduce segundo numero: "; cin >> b; cout << endl; cout << "valor de a: " << a << " valor de b: " << b << endl;
intercambio(&a, &b); cout << endl << "Despues del intercambio: " << endl << endl; cout << "valor de a: " << a << " valor de b: " << b << endl; system("pause"); } void intercambio(int *x, int *y) { int z; z = *x; *x = *y; *y = z; }
La salida de este programa es:
En la llamada, a la función se le envía la dirección de los parámetros. El operador que obtiene la dirección de una variable es &. intercambio(&a, &b); En la cabecera de la función, los parámetros formales que reciben las direcciones deben ser punteros. Esto se indica mediante el operador * void intercambio(int *x, int *y) Los punteros x e y reciben las direcciones de memoria de las variables a y b. Al modificar el contenido de las direcciones x e y, indirectamente estamos modificando los valores a y b. Por tanto, pasar parámetros por referencia a una función es hacer que la función acceda indirectamente a las variables pasadas . Ejemplo 2: En el siguiente ejemplo, se lee una hora (hora, minutos y segundos) y se calcula la hora un segundo después. El programa utiliza una función segundo_despues que recibe la hora, minutos y segundos leídos y los modifica de forma que al finalizar contienen la hora un segundo después. // Hora un segundo después
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
38
#include #include using namespace std; void segundo_despues(int *, int *, int *); int main() { int horas, minutos, segundos; do { cout << "Introduce hora: "; cin >> horas; }while(horas<0 || horas > 23); do { cout << "Introduce minutos: "; cin >> minutos; }while(minutos<0 || minutos > 59); do { cout << "Introduce segundos: "; cin >> segundos; }while(segundos<0 || segundos > 59); //llamada a la función segundo_despues(&horas, &minutos, &segundos); cout << setfill('0'); cout << endl << "Hora un segundo despues: "; cout << setw(2) << horas << ":"; cout << setw(2) << minutos << ":"; cout << setw(2) << segundos << endl; system("pause"); } //function c++ que recibe una hora expresada en //horas, minutos y segundos y calcula la hora //un segundo después void segundo_despues(int *h, int *m, int *s) { (*s)++; if(*s == 60) { *s = 0; (*m)++; if(*m == 60) { *m = 0; (*h)++; if(*h == 24) { *h = 0; } } } }
Esta función no devuelve nada (aparece void como tipo devuelto), por lo que no es necesario poner la instrucción return. Mediante return una función solo puede devolver un valor. En casos como la función anterior en los que es necesario devolver más de un valor, habrá que hacerlo pasando los parámetros por referencia. Este paso de parámetros por referencia basado en punteros es el utilizado por C y por tanto también puede usarse en C++. Pero C++ incorpora una nueva forma de paso de parámetros que no hace uso de punteros. Es el paso de parámetros utilizando referencias.
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
39
2.2 Paso de parámetros utilizando referencias. Una referencia es un nombre alternativo (un alias, un sinónimo) para un objeto. Una referencia no es una copia de la variable referenciada, sino que es la misma variable con un nombre diferente. Utilizando referencias, las funciones trabajan con la misma variable utilizada en la llamada. Si se modifican los valores en la función, realmente se están modificando los valores de la variable original.
Ejemplo: El primer ejemplo del punto anterior utilizando referencias lo podemos escribir así: #include using namespace std; void intercambio(int &, int &); int main( ) { int a, b; cout << "Introduce primer numero: "; cin >> a; cout << "Introduce segundo numero: "; cin >> b; cout << endl; cout << "valor de a: " << a << " valor de b: " << b << endl; intercambio(a, b); cout << endl << "Despues del intercambio: " << endl << endl; cout << "valor de a: " << a << " valor de b: " << b << endl; system("pause"); } void intercambio(int &x, int &y) { int z; z = x; x = y; y = z; }
En la declaración de la función y en la definición se coloca el operador referencia a & en aquellos parámetros formales que son referencias de los parámetros actuales: void intercambio(int &, int &); void intercambio(int &x, int &y)
//declaración de la función //definición de la función
Cuando se llama a la función: intercambio(a, b); se crean dos referencias (x e y) a las variables a y b de la llamada. Lo que se haga dentro de la función con x e y se está haciendo realmente con a y b. La llamada a una función usando referencias es idéntica a la llamada por valor. Ejemplo: El segundo ejemplo anterior, utilizando referencias: // Hora un segundo después #include #include using namespace std; void segundo_despues(int &, int &, int &); int main() { int horas, minutos, segundos; do { cout << "Introduce hora: "; cin >> horas;
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
40
}while(horas<0 || horas > 23); do { cout << "Introduce minutos: "; cin >> minutos; }while(minutos<0 || minutos > 59); do { cout << "Introduce segundos: "; cin >> segundos; }while(segundos<0 || segundos > 59); segundo_despues(horas, minutos, segundos); cout << setfill('0'); cout << endl << "Hora un segundo despues: "; cout << setw(2) << horas << ":"; cout << setw(2) << minutos << ":"; cout << setw(2) << segundos << endl; system("pause"); } void segundo_despues(int &h, int &m, int &s) { s++; if(s == 60) { s = 0; m++; if(m == 60) { m = 0; h++; if(h == 24) { h = 0; } } } }
Otro Ejemplo Funciones Escribir un programa que permita al usuario elegir el cálculo del área de cualquiera de las figuras geométricas: círculo, cuadrado, rectángulo o triángulo mediante funciones. #include #include int n,r,b,a,b1,b2,a2; float circulo(int r); void carga(); float triangulo (int b, int a); float cuadrado (int b1); float rectangulo (int b2, int a2); int main() { carga(); system( “pause”); return 0; }
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
41
void carga () { do { clrscr(); cout<<"1. circulo"<>n; switch (n) { case 1:cout<<"Opcion 1=circulo"<>r; cout<<"El superficie del circulo es:"<>b; cout<<"Ingrese la altura del triangulo:"<>a; cout<<"La superficie del triangulo es:"<>b1; cout<<"La superficie del cuadrado es:"<>b2; cout<<"Ingrese la altura del rectangulo:"<>a2; cout<<"La superficie del rectangulo es:"<
} while (n !=5); }
float circulo(int r) { return ((float)(3.14*r*r)); } float triangulo(int a, int b) { return ((float) (b*a)/2); } float cuadrado (int b1)
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
42
{ return ((float) (b1*b1)); } float rectangulo (int b2, int a2) { return ((float)(b2*a2)); }
Ambito de una variable en C++ El ámbito, alcance o scope de una variable es la parte del programa donde la variable es accesible. Esta definición es también aplicable a constantes y objetos. En C++ existen tres tipos de ámbitos: - Global o de programa - Local o de función. - De bloque. Según su ámbito las variables se clasifican en variables globales, variables locales y variables de bloque. 1. Variables globales. Son variables declaradas fuera de cualquier función, normalmente al comienzo del programa. Las variables globales son accesibles desde su declaración hasta el final del programa por todas las funciones que lo forman. Ejemplo de uso de variables globales en C++: // Ejemplo de variable global #include using namespace std; //se declara x como global. int x = 1; void funcion(); int main() { cout << x << endl; // muestra 1 x++; cout << x << endl, // muestra 2 //se llama a una función que accede a //la variable global x funcion(); cout << x << endl, // muestra 4 system("pause"); } void funcion() { //la función tiene acceso a la variable global x x = x * 2; }
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
43
En el ejemplo se ha declarado la variable x como global. En el momento de la declaración se asigna memoria y comienza a estar accesible. Tanto main como la función tienen acceso a la variable x y por tanto pueden modificar su valor. La variable global deja de estar accesible cuando acaba la ejecución del programa. 2 Variables locales. Las variables locales son las que se declaran dentro de una función. Son accesibles desde el punto donde se declaran hasta el final del bloque donde se han declarado. Los límites de los bloques están definidos por las llaves de apertura y cierre { }. Normalmente el final del bloque coincide con el final de la función. Si el bloque donde se ha declarado la variable local contiene a su vez otros bloques, también son accesibles dentro de ellos. Las variables locales se destruyen cuando se sale del bloque donde han sido declaradas. Los parámetros formales (los que aparecen en la cabecera de una función) se consideran variables locales de la función.
Ejemplo de uso de variables locales: El siguiente programa muestra el uso de variables locales. El programa lee 10 números por teclado y calcula si el número es primo. Para comprobar si el número leído es primo se utiliza una función que recibe el número y devuelve true o false según el número sea primo o no. #include using namespace std; bool es_primo(int); int main() { int numero, i; // variables locales de main cout << "Introduzca 10 numeros enteros > 0: "; for(i=1;i<=10;i++) { do { cout << "numero " << i << ": "; cin >> numero; }while(numero <= 0); if (es_primo(numero)) cout << "Es primo" << endl; else cout << "No es primo" << endl; } system("pause"); } //función que comprueba si un número es primo //el parámetro n es una variable local de la función bool es_primo(int n) { Bool estado=false; int i=2; // i es una variable local de la función if(n==1) estado= true; else { while(n%i!=0) i++; if(i==n) estado= true; } return estado;
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
44
}
Ocultación de variables Puede ocurrir que una variable global y otra local tengan el mismo nombre. Cuando ocurre esto, la variable global queda oculta en el ámbito de accesibilidad de la local del mismo nombre. Para acceder a una variable global que ha quedado oculta por otra local se utiliza el operador de resolución de ámbito :: Ejemplo de ocultación de variables en C++: // Ejemplo de ocultación de variables #include using namespace std; int a = 10; //variable global int main() { int a = 5; //variable local de main //oculta la variable global con el mismo nombre cout << a << endl; //muestra 5 cout << ::a << endl; //acceso a la variable global mediante :: //muestra 10 system("pause"); }
El programa muestra: 5 10 3 Variables de bloque.
Una función puede contener bloques definidos dentro de otros. Los límites de los bloques están definidos por las llaves de apertura y cierre { }. El ámbito de una variable declarada dentro de un bloque comienza en el punto en que se declara hasta el final del bloque donde se ha declarado (llave final del bloque). Una variable de bloque se destruye cuando acaba la ejecución del bloque donde se ha declarado. Un ejemplo muy usual de declaración de variables dentro de un bloque es hacerlo en las instrucciones for: for(int i = 1; i<=20; i+=2) { cout << i << endl; }
La variable i se ha declarado dentro del for y solo es accesible dentro de él. Si a continuación de la llave final del for escribimos: cout << i << endl;
se producirá un error de compilación: la variable i no existe fuera del for y el compilador nos dirá que no está declarada. Una variable puede quedar oculta (no accesible) si hay otro bloque anidado y se declara otra variable con el mismo nombre. La variable declarada en el bloque interior oculta a la primera variable y la hace inaccesible en el bloque interior.
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
45
Sobrecarga de Funciones en C++ Cuando hablamos de sobrecarga de funciones o métodos en C++, hacemos referencia al hecho de que podemos tener más de una función con el mismo nombre a lo largo de nuestro programa, sin embargo no podemos tener exactamente la misma función (de todas formas no tendría sentido), es decir, la variación que debería haber para realizar una sobrecarga exitosa debería ser el tipo de dato que se retorna, o por ejemplo el tipo de dato o la cantidad de parámetros de entrada. Ejemplo la función llevará a cabo la suma de dos números, llamada suma( )…sin embargo ocurre algo especial con esta función, debería ser capaz de realizar la suma recibiendo parámetros de tipo entero y de tipo real (como 3.42 o 8.4765). En el lenguaje C, cuando se declara una función, solo se puede indicar un tipo de dato (int, float, char, double, etc) por cada dato que se recibirá, por lo tanto lo que haremos a continuación es implementar dos funciones que tendrán el mismo nombre suma( ) pero que una recibirá y retornará valores de tipo entero (int) y la otra función recibirá y retornará valores de tipo real ( double ). Vamos a dividir el código completo en 3 partes, para explicar cada una de ellas de forma más entendible. A continuación se presenta la primera parte del programa, con la directiva de preprocesador, el espacio de nombres a usar (en este caso el estándar, std) y luego, los prototipos de la función suma( ) sobrecargada, como puedes notar, ambas funciones tienen el mismo nombre pero los tipos de dato con los que trabaja son diferentes, por lo que es válida la declaración. #include using namespace std; //Prototipos de la función sobrecargada suma( ) int suma(int, int); double suma(double, double);
A continuación se lleva a cabo la definición de la función principal main( ), que dada la finalidad del ejemplo, es muy sencilla, y lo único que hacemos es imprimir en pantalla el resultado de las dos funciones suma. // Definición de la función principal int main(void) { cout<<"2 + 3 = "<
Finalmente realizamos la definición de las finalidad del ejemplo.
“dos” funciones
suma( ) las cuales resultan ser muy básicas, por la
//Definición de la función suma sobrecargada...para enteros y reales int suma(int a, int b) { return (a+b); } double suma(double a, double b) { return (a+b); }
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
46
Lo que sucede cuando el compilador encuentra funciones sobrecargadas , es “ver ” cuáles son los tipos de dato que se pasan a dicha función o la cantidad de los mismos (ya que estos pueden variar) y ver cuál de todas las funciones cumple con dichas especificaciones y hacer el llamado respectivo. Por último, solo queda recordar, que para realizar una buena sobrecarga de funciones , solo hay que tener en cuenta que todas las funciones del mismo nombre tienen que diferir en algo en sus prototipos, ya sean en los tipos de datos recibidos o retornados, la cantidad de argumentos, etc; incluso si el cuerpo de las mismas es completamente diferente, lo importante es lo que mencionábamos anteriormente. Finalmente, a continuación se encuentra el código completo, listo para compilar y ejecutar. #include using namespace std; //
Ejemplo de sobrecarga de funciones en C++
//Prototipos de la función sobrecargada suma( ) int suma(int, int); double suma(double, double); // Definición de la función principal int main(void) { cout<<"2 + 3 = "<
Arrays / Vectores /Arreglos en C++ Un array es una colección finita de datos del mismo tipo, que se almacenan en posiciones consecutivas de memoria y reciben un nombre común.
Ejemplo de array: Supongamos que queremos guardar las notas de los 20 alumnos de una clase. Para ello utilizaremos un array de 20 elementos y en cada elemento almacenaremos una nota. Podemos representar gráficamente el array de notas de la siguiente forma: Array notas:
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
47
Para acceder a cada elemento del array se utiliza el nombre del array y uno o más índices que indican la posición que ocupa el elemento dentro del array. Cada índice se escribe entre corchetes. El primer elemento del array ocupa la posición 0 , el segundo la posición 1, etc. En un array de N elementos el último ocupará la posición N-1. En el ejemplo anterior, notas[0] contiene la nota del primer alumno y notas[19] contiene la del último
Cómo declarar un array: Un array se declara de forma parecida a una variable de tipo simple añadiéndole al nombre el número de elementos que contendrá el array. De forma general, un array se declara así: tipo_dato nombre_array[elementos1][elementos2]…..;
elementos1, elementos2, etc. son los índices del array. Deben ser números enteros positivos o expresiones con un resultado entero positivo. Indican el número de elementos del array. En el ejemplo anterior, el array notas se declara como: double notas[20]; El array es unidimensional, se llama notas y contiene 20 elementos de tipo double. Más ejemplos de declaración de arrays: int ventas[10] ; //array llamado ventas que contiene 10 enteros double grados[20]; //array grados que contiene 20 elementos de tipo double float precios[30]; //array llamado precios que contiene 30 elementos de tipo float
El número de índices determina la dimensión del array . Si el array tiene solo un índice es un array de una dimensión o unidimensional (también llamado vector), si tiene dos índices es un array de dos dimensiones o bidimensional (también llamados matrices, tablas o arreglos), si tienen tres índice tridimensional, etc. Para facilitar la modificación del programa, el tamaño del array se puede declarar utilizando una constante en lugar de una cantidad entera. Esto hace más fácil modificar el programa ya que todas las referencias al tamaño máximo del array (por ejemplo, en bucles for o en definiciones de arrays) pueden ser modificadas cambiando el valor de la constante. Por ejemplo, declaración de 4 arrays A, B, C y D de 10 elementos cada uno de tipo double usando una constante llamada ELEMENTOS: const int ELEMENTOS = 10; double A[ELEMENTOS], B[ELEMENTOS], C[ELEMENTOS], D[ELEMENTOS]; En este caso si se modifica el tamaño de los arrays, solo habrá que cambiar el valor de la constante. Los arrays declarados como locales en una función tienen como valores iniciales valores indeterminados, como ocurre con las variables locales.
La declaración de un array puede incluir la asignación de valores iniciales . La forma general de hacerlo es: tipo nombre_array[tamaño]={valor1,valor2,..,valorn}; Donde valor1 es el valor del primer elemento del array, valor2 el valor del segundo elemento, y así sucesivamente. El tamaño del array es opcional cuando se asignan valores iniciales en la declaración. Todos los elementos del array que no tienen asignados valores iniciales explícitos, (sucede cuando un array tienes más elementos que valores iniciales se han asignado), serán puestos automáticamente a cero.
Ejemplos de asignación de valores iniciales en la declaración de un array en C++: double porcentaje[]={0, 0.3, 7.25, 4.2};
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
48
Se declara un array unidimensional llamado porcentaje que contiene 4 elementos de tipo double. El número de elementos no es necesario indicarlo porque se están asignando4 valores iniciales. El compilador asume que el array tiene 4 elementos. int numeros[5]= {1,4,-7,5,9}; Se declara un array unidimensional llamado numeros que contiene 5 elementos de tipo int. Se indica el número de elementos aunque no es necesario hacerlo. Se están asignando 5 valores iniciales. El compilador asume que el array tiene 5 elementos. int digitos[8]= {3,4,2,7}; Se declara un array unidimensional llamado digitos que contiene 8 elementos de tipo int. Aquí sí es necesario indicar el número de elementos del array porque solo se le asignan valores iniciales a los cuatro primeros. El compilador asumiría que el array tiene solo 4 elementos. En este caso los cuatro últimos elementos del array que no reciben valores iniciales, toman el valor 0. digitos[0]=3, digitos[1]=4, digitos[2]=2, digitos[3]=7, digitos[4]=0, digitos[5]=0, digitos[6]=0, digitos[7]=0 Las declaraciones de arrays que hemos hecho hasta ahora se llaman declaraciones implícitas: para cada array que se declara hay que indicar el tipo y la dimensión. Una alternativa a esto es definir un nuevo tipo de dato para el array asignándole un nombre, y posteriormente declarar las variables como pertenecientes a ese tipo. C++ dispone del especificador typedef que permite la creación de nuevos tipos de datos. Los tipos de datos creados con typedef son sinónimos de otros tipos ya existentes. Por ejemplo, la siguiente instrucción crea un nuevo tipo de dato llamado entero, sinónimo de int. typedef int entero;
A partir de esta instrucción podemos declarar variables enteras así: entero a, b=3; Utilizando typedef podemos crear nuevos tipos de datos sinónimos de tipos array. La forma general de hacerlo es:
typedef tipo_base nombre_nuevo_tipo[dimension]; Ejemplo:
typedef int Tvector[30]; Esta instrucción crea un nuevo tipo de dato llamado Tvector. Las variables que se declaren de este tipo serán arrays de 30 enteros. Por ejemplo: Tvector a, b;
Ejemplo: Generar 2 vectores (a y b) con números aleatorios. Sumar sus elementos en otro vector llamado s. Mostrar todos los vectores #include using namespace std; const int n=10;
void cargarvector(int v[n]); void sumar(int x[n],int y[n],int s[n]); void mostrarvec(int v[n]); int main() { int a[n],b[n],s[n]; cargarvector(a); cargarvector(b); sumar(a,b,s); cout<<"vector a"<
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
49
mostrarvec(a); cout<<"vector b"<
void cargarvector(int v[n]) { int i; srand(time(NULL)) for(i=0;i
Vectores Bidimensionales o Matrices Un vector multidimensional, es un vector de vectores. Una matriz es un vector bidimensional. Declaración de una matriz: int vector[filas][columnas]; int a[5][5],m[10][4],i,j,f,c // Ejemplo: int vector[5][3];
nombre del vector y dimensión
Su representación es:
Lectura de una Matriz (llenado): for (i=0; i<5;i++)
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
Cada elemento se referencia a través del nombre y su ubicación en el
50
{ for (j=0; j < 5 ; j=j+1) { Cout<<”\n Ingrese elemento A[“<
=
Cin>>a[i][j]; } }
conjunto, por ejemplo: { a[4][2]=10; // Se almacena en la fila 5, columna 3 el valor 10 m[0][5]=0; // Se almacena en la fila uno, columna 6 el valor 0 if (a[i][j] == a[j][i] ) // se consulta si el valor ubicado en la fila i-1 y columna j-1 es igual al elemento // almacenado en la fila j-1 y columna i-1 }
Consideraciones importantes asociadas al uso de matrices: • • • •
El procesamiento de todos los elementos requiere como mínimo dos ciclos iterativos. Dentro de los ciclos se deben realizar las operaciones específicas que se solicitan. Una matriz cuadrada es aquella en el numero de filas es igual al número de c olumnas. Entre las aplicaciones más importantes de las matrices está la posibilidad de resolver sistemas de ecuaciones con n
variables. Las matrices cuadradas tienen algunas características importantes asociadas a la ubicación de sus elementos en el conjunto. Se puede hablar de diagonal principal, diagonal secundaria, triangular superior, triangular inferior, por mencionar algunas.
Ordenamiento de Vectores Es la operación de arreglar los registros de una tabla en algún orden secuencial de acuerdo a un criterio de ordenamiento. El ordenamiento se efectúa con base en el valor de algún campo en un registro. El propósito principal de un ordenamiento es el de facilitar las búsquedas de los miembros del conjunto ordenado. El ordenar un grupo de datos significa mover los datos o sus referencias para que queden en una secuencia tal que represente un orden, el cual puede ser numérico, alfabético o incluso alfanumérico, ascendente o descendente.
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
51
Ordenamiento Por Selección (Selection Sort) • • • • •
Busca el elemento más pequeño de la lista. Intercambia con el elemento ubicado en la primera posición de la lista. Busca el segundo elemento más pequeño de la lista. Lo intercambia con el elemento que ocupa la segunda posición en la lista. Repite este proceso hasta que haya ordenado toda la lista.
ANÁLISIS DEL ALGORITMO. • Requerimientos de Memoria: Al igual que el ordenamiento burbuja, este algoritmo sólo necesita una variable
adicional para realizar los intercambios.
• Tiempo de Ejecución: El ciclo externo se ejecuta n veces para una lista de n elementos. Cada búsqueda
requiere comparar todos los elementos no clasificados. Ventajas: • Fácil implementación. • No requiere memoria adicional. • Rendimiento constante: poca diferencia entre el peor y el mejor caso.
Desventajas: • Lento. • Realiza numerosas comparaciones #include Using namespace std; void seleccionsort(int vector[15],int tamano); void mostrarVector(int[], int); int _main( ) { const int tamano = 15; int vector[tamano] = {25,17,13,16,41,32,12,115,95,84,54,63,78,21,10}; int i; cout << "vector sin ordenar\n" ; mostrarVector(vector,tamano); cout << "vector ordenado\n" ; seleccionsort(vector,tamano); mostrarVector(vector,tamano); system(“pause”);
return 0; } void seleccionsort (int A[], int n) { int min,i,j,aux; for (i=0; i A[j]) {min=j; aux=A[min]; A[min]=A[i]; A[i]=aux ;} } } }
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
52
void mostrarVector( int vector[], int tamano) { for (int i = 0 ; i < tamano ; i++) cout << vector[i] << "/"; cout<<"\n"; }
Ordenamiento BubbleSort o Burbuja o Intercambio Directo. Es un sencillo algoritmo de ordenamiento. Funciona revisando cada elemento de la lista que va a ser ordenada con el siguiente, intercambiándolos de posición si están en el orden equivocado. Es necesario revisar varias veces toda la lista hasta que no se necesiten más intercambios, lo cual significa que la lista está ordenada. Este algoritmo obtiene su nombre de la forma con la que suben por la lista los elementos durante los intercambios, como si fueran pequeñas "burbujas". También es conocido como el método del intercambio directo. Dado que solo usa comparaciones para operar elementos, se lo considera un algoritmo de comparación, siendo el más sencillo de implementar. #include Using namespace std; void BubbleSort(int vector[15],int tamano); void mostrarVector(int[], int); int main( int argc, _TCHAR* argv[]) { const int tamano = 15; int vector[tamano] = {20,17,13,16,41,32,12,115,95,84,54,63,78,21,10}; int i; cout << "vector sin ordenar\n" ; mostrarVector(vector,tamano); cout << "vector ordenado\n" ; BubbleSort(vector,tamano); mostrarVector(vector,tamano); system(“pause”);
return 0; } //----------------------------------------------------------------void BubbleSort(int A[],int n) {int i, j, inc, temp, k,item ; for (i = 1; i A[j + 1]) { temp = A[j]; A[j] = A[j + 1] ; A[j + 1] = temp; } } } } void mostrarVector( int vector[], int tamano) { for (int i = 0 ; i < tamano ; i++) cout << vector[i] << "/";
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
53
cout<<"\n"; }
Ordenamiento Por Inserción Directa DESCRIPCIÓN. El algoritmo de ordenación por el método de inserción directa es un algoritmo relativamente sencillo y se comporta razonablemente bien en gran cantidad de situaciones. Completa la tripleta de los algoritmos de ordenación más básicos y de orden de complejidad cuadrático, junto con SelectionSort y BubbleSort. Se basa en intentar construir una lista ordenada en el interior del array a ordenar. De estos tres algoritmos es el que mejor resultado da a efectos prácticos. Realiza una cantidad de comparaciones bastante equilibrada con respecto a los intercambios, y tiene un par de características que lo hacen aventajar a los otros dos en la mayor parte de las situaciones. Este algoritmo se basa en hacer comparaciones, así que para que realice su trabajo de ordenación son imprescindibles dos cosas: un array o estructura similar de elementos comparables y un criterio claro de comparación, tal que dados dos elementos nos diga si están en orden o no. • En cada iteración del ciclo externo los elementos 0 a i forman una lista ordenada
ANÁLISIS DEL ALGORITMO. • Estabilidad: Este algoritmo nunca intercambia registros con claves iguales. Por lo tanto es estable. • Requerimientos de Memoria: Una variable adicional para realizar los intercambios. • Tiempo de Ejecución: Para una lista den elementos el ciclo externo se ejecuta n 1 veces. El ciclo interno se
ejecuta como máximo una vez en la primera iteración, 2 veces en la segunda, 3 veces en la tercera, etc.
Ventajas: • Fácil implementación. • Requerimientos mínimos de memoria.
Desventajas: • Lento. • Realiza numerosas comparaciones.
Este también es un algoritmo lento, pero puede ser de utilidad para listas que están ordenadas o semi ordenadas, porque en ese caso realiza muy pocos desplazamientos. void insercionDirecta(int A[],int n) { int i,j,v; for (i = 1; i < n; i++) { v = A[i]; j=i -1;
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
54
while (j >= 0 && A[j] > v) { A[j + 1] = A[j]; j--; }A[j+ 1] = v ; } }
Método De Ordenamiento Por Inserción Binaria El método de ordenación por 'inserción binaria'' es una mejora del método de inserción directa. Para lograr e sta mejora se recurre a una búsqueda binaria en lugar de una búsqueda secuencial para insertar un elemento en la parte izquierda del vector, que ya se encuentra ordenado. El resto del procedimiento es similar al de inserción directa, es decir, se repite este mismo procedimiento desde el segundo término hasta el último elemento. void insercionBinaria(int A[],int n) { int i,j,aux,izq,der,m; for(i=1;i=izq) { A[j+1]=A[j]; j=j-1; }A[izq]=aux; } }
Ordenamiento por el Método Shell El método Shell es una versión mejorada del método de inserción directa. Este método también se conoce con el nombre de inserción con incrementos decrecientes. En el método de ordenación por inserción directa cada elemento se compara para su ubicación correcta en el vector, con los elementos que se encuentran en la parte izquierda del mismo. Si el elemento a insertar es más pequeño que el grupo de elementos que se encuentran a su izquierda, es necesario efectuar entonces varias comparaciones antes de su ubicación. Shell propone que las comparaciones entre elementos se efectúen con saltos de mayor tamaño pero con incrementos decrecientes, así, los elementos quedarán ordenados en el vector más rápidamente.
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
55
El Shell sort es una generalización del ordenamiento por inserción, teniendo en cuenta dos observaciones: 1. El ordenamiento por inserción es eficiente si la entrada está "casi ordenada". 2. El ordenamiento por inserción es ineficiente, en general, porque mueve los valores sólo una posición cada vez. El algoritmo Shell sort mejora el ordenamiento por inserción comparando elementos separados por un espacio de varias posiciones. Esto permite que un elemento haga "pasos más grandes" hacia su posición esperada. Los pasos múltiples sobre los datos se hacen con tamaños de espacio cada vez más pequeños. El último paso del Shell sort es un simple ordenamiento por inserción, pero para entonces, ya está garantizado que los datos del vector están casi ordenados. El Shell sort lleva este nombre en honor a su inventor, Donald Shell, que lo publicó en 1959. #include Using namespace std; void ordenShell(int vector[15],int tamano); void mostrarVector(int[], int);
int main( ) { const int tamano = 15; int vector[tamano] = {25,17,13,16,41,32,12,115,95,84,54,63,78,21,10}; int i; cout << "vector sin ordenar\n" ; mostrarVector(vector,tamano); cout << "vector ordenado\n" ; ordenShell(vector,tamano); mostrarVector(vector,tamano); system(“pause”);
return 0; } //--------------------------------------------------------------------------void ordenShell(int A[],int n) {int i, j, inc, temp; for(inc = 1 ; inc 0) { for (i=inc; i < n; i++) { j = i; temp = A[i]; while ((j >= inc) && (A[j-inc] > temp)) { A[j] = A[j - inc]; j = j - inc; } A[j] = temp; } inc/= 2; } } void mostrarVector( int vector[], int tamano) { for (int i = 0 ; i < tamano ; i++) cout << vector[i] << "/"; cout<<"\n"; }
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
56
Ordenamiento Heap Sort El ordenamiento por montículos (Heap sort) es un algoritmo de ordenación no recursivo, no estable. Este algoritmo consiste en almacenar todos los elementos del vector a ordenar en un montículo (heap), y luego extraer el nodo que queda como nodo raíz del montículo (cima) en sucesivas iteraciones obteniendo el conjunto ordenado. Basa su funcionamiento en una propiedad de los montículos, por la cual, la cima contiene siempre el menor elemento (o el mayor, según se haya definido el montículo) de todos los almacenados en él. El significado de heap en ciencia computacional es el de una cola de prioridades (priority queue). Tiene las siguientes características: Un heap es un vector de n posiciones ocupado por los elementos de la cola. (Nota: se utiliza un vector que inicia en la posición 1 y no en cero, de tal manera que al implementarla en C se tienen n+1 posiciones en el vector.) Se mapea un árbol binario de tal manera en el vector que el nodo en la posición i es el padre de los nodos en las posiciones (2*i) y (2*i+1). El valor en un nodo es mayor o igual a los valores de sus hijos. Por consiguiente, el nodo padre tiene el mayor valor de todo su subárbol. PROCEDIMIENTO Heap Sort consiste esencialmente en: • Convertir el vector en un heap • Construir un vector ordenado de atrás hacia adelante (mayor a menor) repitiendo los siguientes pasos: • Sacar el valor máximo en el heap (el de la posición 1) • Poner ese valor en el vector ordenado • Reconstruir el heap con un elemento menos • Utilizar el mismo vector para el heap y el vector ordenado #include using namespace std; void heapsort(int vector[15],int tamano); void mostrarVector(int[], int); int _tmain( ) { const int tamano = 15; int vector[tamano] = {0,17,13,16,41,32,12,115,95,84,54,63,78,21,10}; int i; cout << "vector sin ordenar\n" ; mostrarVector(vector,tamano); cout << "vector ordenado\n" ; heapsort(vector,tamano); mostrarVector(vector,tamano); system(“pause”);
return 0; } //-----Este método comienza en la posición 1!!! ---------------------
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
57
void heapsort(int A[],int n) {int i, j, inc, temp, k,item ; for(k=n;k>0;k--) { for(i=1;i<=k;i++) { item=A[i]; j=i/2; while(j>0 && A[j]
Búsqueda de elementos en un Vector La búsqueda de un elemento dentro de un array es una de las operaciones más importantes en el procesamiento de la información, y permite la recuperación de datos previamente almacenados. El tipo de búsqueda se puede clasificar como interna o externa, según el lugar en el que esté almacenada la información (en memoria o en dispositivos externos). Todos los algoritmos de búsqueda tienen dos finalidades: - Determinar si el elemento buscado se encuentra en el conjunto en el que se busca. - Si el elemento está en el conjunto, hallar la posición en la que se encuentra. En este apartado nos centramos en la búsqueda interna. Como principales algoritmos de búsqueda en arrays tenemos la búsqueda secuencial, la binaria y la búsqueda utilizando tablas de hash.
Búsqueda secuencial Consiste en recorrer y examinar cada uno de los elementos del array hasta encontrar el o los elementos buscados, o hasta que se han mirado todos los elementos del vector. void secuencia(int a[n1],int k1) { int cual,x1; bool ubicado=false; cout<<"Que elemento se buscara? : ";cin>>cual; cout<
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
58
{ ubicado=true; cout<<"Elemento encontrado en la posicion "<
Búsqueda binaria La búsqueda binaria sólo se puede implementar si el vector está ordenado. La idea consiste en ir dividiendo el vector en mitades. Por ejemplo supongamos que tenemos este vector: int vector[10] =
{2,4,6,8,10,12,14,16,18,20};
La clave que queremos buscar es 6. El algoritmo funciona de la siguien manera 1. Se determinan un indice arriba y un indice abajo, Iarriba=0 e Iabajo=9 respectivamente. 2. Se determina un indice central, Icentro = (Iarriba + Iabajo)/2, en este caso quedaría Icentro = 4. 3. Evaluamos si vector[Icentro] es igual a la clave de busqueda, si es igual ya encontramos la clave y devolvemos Icentro. 4. Si son distintos, evaluamos si vector[Icentro] es mayor o menos que la clave, como el vector está ordenado al hacer esto ya podemos descartar una mitad del vector asegurandonos que en esa mitad no está la clave que buscamos. En nuestro caso vector[Icentro] = 4 < 6, entonces la parte del vector vector[0...4] ya puede descartarse. 5. Reasignamos Iarriba o Iabajo para obtener la nueva parte del vector en donde queremos buscar. Iarriba, queda igual ya que sigue siendo el tope. Iabajo lo tenemos subir hasta 5, entonces quedaria Iarriba = 9, Iabajo = 5. Y volvemos al paso 2. Si la clave no fuese encontrada en algun momento Iabajo > Iarriba, con un while vamos a controlar esta condición para salir del ciclo en tal caso y devolver -1 (clave no encontrada). Hagamos modificaciones al código de búsqueda lineal para implementar una función de búsqueda binaria. //Búsqueda binaria en un vector.
#include using namespace std; int busquedaBinaria(const int[], int, int); //vector, tamaño, clave void ordenarVector(int[], int); //prototipo que modifica y ordena el vector void intercambiar(int&, int&); //prototipo, intercambia los valores de dos elementos void mostrarVector(int[], int); //-------------------------------------------------------------------#pragma argsused int main() { int clave =0; const int tamano = 15; int vector[tamano] = {20,17,13,16,41,32,12,115,95,84,54,63,78,21,10}; int i; //ordenamos el vector para que funcione la busquedaBinaria
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
59
cout << "Vector sin ordenar\n" ; mostrarVector(vector,tamano); ordenarVector(vector,tamano); cout << "Elementos del vector ordenado:\n"; mostrarVector(vector,tamano); cout << "Indique un valor a buscar y se le devolvera el indice: " ; cin >> clave; cout<< "Su valor se encuentra en vector["<
return 0; } void mostrarVector( int vector[], int tamano) { for (int i = 0 ; i < tamano ; i++) cout << vector[i] << "/"; cout<<"\n"; } int busquedaBinaria(const int vector[], int tamano, int clave) { int Iarriba = tamano-1; int Iabajo = 0; int Icentro; while (Iabajo <= Iarriba) { Icentro = (Iarriba + Iabajo)/2; if (vector[Icentro] == clave) return Icentro; else if (clave < vector[Icentro]) Iarriba=Icentro-1; else Iabajo=Icentro+1; } return -1; } void ordenarVector(int vector[], int tamano) { for (int i = 0; i< tamano -1 ; i++) for (int j = 0; j< tamano -1 ; j++) if (vector[j] > vector[j+1]) intercambiar(vector[j],vector[j+1]); } void intercambiar(int &a, int &b) { int tmp = b; b = a; a = tmp; }
Archivos Hasta ahora, siempre hemos leído mediante cin, y escrito mediante cout. Sin embargo, a veces es cómodo utilizar uno o más (todos los que queramos) archivos de texto de donde sacar los datos, y similarmente escribir a uno o más archivos los resultados de nuestro programa.
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
60
En C++, utilizar archivos es muy fácil, ya que la forma de hacerlo es prácticamente igual a lo que ya venimos haciendo con cin y cout. Para utilizar archivos y hacer funcionar los ejemplos de esta sección, tendremos que incluir #include en nuestros programas.
Archivos de entrada Es posible crear una variable que represente un archivo de entrada, del cual el programa leerá datos. Estas variables se utilizan de exactamente igual manera que cin, y se declaran como en el siguiente programa de ejemplo: #include using namespace std; int main() { ifstream archivo1("nombre1.txt"); ifstream archivo2("nombre2.in"); int x,y,z; archivo1 >> x>> y >> z; string a; int b; archivo2 >> a >> b; return 0; }
En el ejemplo se ve que podemos leer datos contenidos en los archivos exactamente igual que hacíamos con cin, pero indicando la variable del archivo correspondiente. En lugar de tener que ser tipeados por el usuario, el programa recibe los datos contenidos en los archivos correspondientes. Las variables son de tipo ifstream (Del inglés, “Input File Stream”), y al declararlas se indica entre paréntesis el nombre del archivo del cuál se leerá
utilizando esa variable. Dicho archivo debe existir y contener los datos deseados, al momento de ejecutar el programa. En este ejemplo se usan dos archivos distintos: El contenido de “nombre1.txt” se guarda en x,y,z (que tendrán 3 enteros) y el de “nombre2.in” se guarda en a,b (Un string y un entero).
Archivos de salida Los archivos de salida se pueden utilizar de manera completamente análoga a los de entrada, pero operando como si fueran cout, y su tipo será ofstream (Del inglés “Output File Stream”). #include using namespace std; int main() { ofstream archivo1("nombre1.txt"); ofstream archivo2("nombre2.out"); int x = 32,y = 10; archivo1 << x << " " << y << " " << -33 << endl; string a = "pepe"; int b = 100; archivo2 << a << endl << b << endl; return 0; }
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
61
Luego de ejecutar este programa, “nombre1.txt” contendrá lo siguiente: 32 10 -33
y “nombre2.out” contendrá lo siguiente: pepe 100
Registros / Data Structures / Estructuras El lenguaje C++ permite definir variables que combinen diferentes ítems/ tipos de datos. A esto se le llama registros. Por ejemplo. El siguiente es un programa que contendrá un registro llamado Netjuegos con los siguientes campos: id_juego; Nick_jugador; nombre_juegos; puntaje_jugador; dia_mes_anio. Crear un archivo plano llamado juegos.in que contenga los siguientes datos: En donde el primer número(15) representa la cantidad de registros. 15 123222 213323 112326 131234 244329 876789 324243 878976 564635 647643 875785 437253 436572 984394 978438
daniel selena ciclo_ nester cheste alpase lechne casior veg777 alexLO redox_ astero segova vipter omega_
counter-strike counter-strike counter-strike counter-strike counter-strike -----LOL----------LOL----------LOL----------LOL----------LOL-------minecraft----minecraft----minecraft----minecraft----minecraft---
9776 6587 4355 3456 1424 5334 4223 3003 2322 1023 100000 845784 679864 45678 20000
02-noviembre-2017 04-noviembre-2017 05-noviembre-2017 07-noviembre-2017 10-noviembre-2017 08-octubre-2017 12-octubre-2017 14-cotubre-2017 20-julio-2017 23-octubre-2017 04-febrero-2018 07-febrero-2018 13-febrero-2018 23-febrero-2018 26-febrero-2018
Se solicita: leer los datos del archivo y mostrarlos por pantalla. #include #include const int maximo=256; using namespace std; int n; struct Netjuegos { int id_juego; char nick_jugador[maximo]; char nombre_juego[máximo]; int puntaje_jugador; char dia_mes_ano[máximo];
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
62
}; ifstream ent; ofstream sal; void leer_datos(struct Netjuegos Art[maximo]); void mostrar_datos(struct Netjuegos Art[maximo); int main() { struct Netjuegos Art[máximo]; ent.open("juegos.in"); leer_datos(Art); mostrar_datos(Art); system("pause"); return 0; } void leer_datos (struct Netjuegos Art[maximo]) { int i; ent>>n; for(i=0;i>Art[i].id_juego>>Art[i].nick_jugador>>Art[i].nombre_juego>>Art[i].puntaj e_jugador>>Art[i].dia_mes_ano; } } void mostrar_datos (struct Netjuegos Art[maximo]) { int i; cout<<"id_juego nick_jugador nombre_juego puntaje_jugador dia_mes_año"<
Tratamiento de Cadenas CHAR como "arreglos o vector de char", "cadenas", o "cstring". DE COPIA: strcpy () Copiar una cadena y pegarla sobre otra.
Copia la cadena apuntada por "fuente" al arreglo apuntado por "destino", insertando por s u cuenta el caracter de fin de cadena (barra invertida cero). Hay que destacar que para que el programa no explote al realizar esta operación, el arreglo "destino" tiene que tener un tamaño de por lo menos la cantidad de caracteres que haya en "fuente" + 1 (espacio para el caracter de fin de cadena) o dicho de otra forma: tamaño mínimo de destino debe ser >= strlen( fuente ) + 1.
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
63
Valor de retorno: puntero a "destino".
strncpy() Copia los primeros "n" caracteres de una cadena a otra.
Copia los primeros "cuantos" caracteres de "fuente" a "destino". Si el final de la cadena "fuente" (indicado por el caracter de fin de cadena 'barra invertida cero' ) es alcanzado antes de que se copien la cantidad de caracteres indicados por "cuantos", el arreglo "destino" se llena con ceros hasta que una cantidad de "cuantos" caracteres hayan sido escritos en él. Valor de retorno: puntero a "destino" .
// Ejemplo de uso en C++ #include #include using namespace std; int main () { const int tamanyo = 40; char cad1[]= "Ser o no ser"; char cad2[tamanyo]; char cad3[tamanyo]; /* Copiar la cantidad máxima permitida por cad2 */ strncpy( cad2, cad1, tamanyo ); /* copia parcial (colamente 5 chars): */ strncpy( cad3, cad2, 5 ); cad3[5] = '\0'; /* caracter de fin de cadena agregado manualmente */ cout<
Salida: Ser o no ser Ser o no ser Ser o
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
64
DE CONCATENACIÓN:
strcat() Concatena dos cadenas.
Pega una copia de la cadena "fuente" al final de la cadena "destino". El "pegado" se produce desde la posición del caracter nulo o de fin de cadena (barra invertida cero) en "destino", sobreescribiéndolo con el primer caracter de "fuente" y continuando. Un nuevo caracter de fin de cadena es insertado al final del proceso. Como con strcpy(), hay que resaltar que el arreglo "destino" tiene que tener un tamaño suficiente para anexar su contenido a la cadena "fuente" , es decir: tamaño de destino >= strlen( destino ) + strlen( fuente ) + 1.
Valor de retorno: un puntero a "destino".
Ejemplos de uso: // Ejemplo de uso en C++ #include #include using namespace std; int main () { char cad[80]; char cad2[] = "estan "; strcpy( cad, "estas " ); strcat( cad, "cadenas " ); strcat( cad, cad2 ); strcat( cad, "concatenadas." ); cout<
Salida: estas cadenas estan concatenadas.
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
65
strncat() Concatena los primeros "n" caracteres de una cadena al final de otra.
Pega los primeros "cuantos" caracteres de fuente al final de "destino", agregando solo el caracter de fin de cadena. Si el tamaño de la cadena "fuente" es menor a la cantidad de caracteres "cuantos", se copiará y pegará solamente los caracteres que haya hasta llegar al caracter de fin de cadena de "fuente". Se deben tener las mismas precauciones de tamaños de arreglos que las indicadas para strcat(). Valor de retorno: puntero a "destino". Ejemplos de uso:
// Ejemplo de uso en C++ #include #include using namespace std; int main () { char cad1[20]; char cad2[20]; strcpy( cad1, "Ser " ); strcpy( cad2, "o no ser" ); strncat( cad1, cad2, 4 ); cout<
Salida: Ser o no
DE COMPARACIÓN:
strcmp() Compara si dos cadenas son iguales.
Compara la cadena "cad1" con la cadena "cad2".
Esta función comienza comparando el primer caracter de cada cadena. Si estos caracteres son iguales, continua con el siguiente par hasta que los caracteres comparados son distintos o se alcanza un caracter nulo o de fin de
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
66
cadena. Valor de retorno: retorna un valor int que indica la relación entre las dos cadenas: Un valor 0 (cero) indica que las dos cadenas son iguales. - Un valor mayor a cero indica que el primer caracter encontrado que es distinto tiene un valor mayor en cad1 que en cad2. - Un valor menor a cero indica lo contrario a lo anterior.
// Ejemplo de uso en C++ #include #include using namespace std; int main () { char clave[] = "manzana"; char entradaClave[80]; do { cout<<"Cual es mi fruta preferida? "; cin.getline( entradaClave, 80 ); } while ( strcmp( clave, entradaClave ) != 0 ); cout<<"Respuesta correcta!"; return 0; }
strncmp() Compara si los primeros "n" caracteres de una cadena son iguales a los primeros "n" caracteres de otra.
Compara los primeros "cuantos" caracteres de la cadena "cad1" con los primeros "cuantos" caracteres de la cadena "cad2".
Esta función comienza comparando el primer caracter de cada cadena. Si estos caracteres son iguales, continua con el siguiente par hasta que los caracteres comparados son distintos, o se alcanza un caracter nulo o de fin de cadena, o hasta que "cuantos" caracteres ah sido comparados y encontrados iguales, lo que pase primero. Valor de retorno: retorna un valor int que indica la relación entre las dos cadenas: Un valor 0 (cero) indica que las dos cadenas son iguales. - Un valor mayor a cero indica que el primer caracter encontrado que es distinto tiene un valor mayor en cad1 que en cad2.
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
67
- Un valor menor a cero indica lo contrario a lo anterior.
// Ejemplo de uso en C++ #include #include using namespace std; int main () { char str[][5] = { "R2D2" , "C3PO" , "R2A6" }; cout<<"Buscando astromech droids R2..."<
DE BÚSQUEDA:
strrchr() Busca en la cadena la última ocurrencia de un caracter (char) indicado. // Ejemplo de uso en C++ #include #include using namespace std; int main () { char str[] = "Esta es una cadena de ejemplo"; char * pch; cout<<"Buscando el caracter 's' en \""<
Salida:
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
68
Buscando el caracter 's' en "Esta es una cadena de ejemplo"... Encontrado en la posicion 2 El puntero retornado apunta a: sta es una cadena de ejemplo Encontrado en la posicion 7 El puntero retornado apunta a: s una cadena de ejemplo
strcspn() Busca en una cadena la primera ocurrencia de cualquiera de los caracteres de otra cadena y retorna la posición de la misma.
Retorna un puntero a la última ocurrencia de "letra" en "cad". El caracter de fin de cadena es considerado parte de la cadena, por lo que puede ser buscado para obtener un puntero al final de la misma. Valor de retorno: Un puntero a la última ocurrencia de "letra" en "cad". Si el caracter no es encontrado, devuelve NULL. Ejemplos de uso:
// Ejemplo de uso en C++ #include #include using namespace std; int main () { char str[] = "Esta es una cadena de prueba"; char * pch; pch = strrchr( str, 's' ); cout<<"La ultima ocurrencia de 's' fue encontrada en la posicion "<
Salida: La ultima ocurrencia de 's' fue encontrada en la posicion 7 El puntero retornado apunta a: s una cadena de prueba
strpbrk() Busca en una cadena la primera ocurrencia de cualquiera de los caracteres de otra cadena y retorna un puntero a char con la subcadena formada desde esa posición.
Retorna un puntero a la primera ocurrencia en "cad1" de cualquiera de los caracteres contenidos en "cad2", o un puntero a NULL si no hubo coincidencias.
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
69
La búsqueda no incluye al caracter de fin de cadena de ninguno de los dos cstrings, pero termina ahí. Ejemplos de uso:
// Ejemplo de uso en C++ #include #include using namespace std; int main () { char cadena[] = "Esto es un cstring de prueba"; char claves[] = "aeiou"; char * pch; cout<<"Vocales en '"<
Salida: Vocales en 'Esto es un cstring de prueba': o e u i e u e a
strspn() Retorna el largo de la porción inicial de una cadena que está formada solamente por los caracteres presentes en otra. Retorna la longitud de la porción inicial de "cad1" que consiste solamente de caracteres que son parte de "cad2". La búsqueda no incluye el caracter de fin de cadena de ninguna de las dos cadenas, pero termina en ese punto. Valor de retorno: la longitud de la porción inicial de "cad1" que consiste solamente de caracteres que son parte de "cad2". Por lo tanto, si todos los caracteres de "cad1" están en "cad2" la función retorna el largo de "cad1", y si el primer caracter de "cad1" no está en "cad2" la función retorna cero. Ejemplos de uso:
// Ejemplo de uso en C++ #include
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
70
#include using namespace std; int main () { char cadena[] = "129asd"; char numeros[] = "1234567890"; int i = strspn( cadena, numeros ); cout<<"El numero inicial de la cadena tiene "<< i <<" digitos."; return 0; }
Salida: El numero inicial de la cadena tiene 3 digitos.
strstr() Busca una cadena dentro de otra cadena, retorna un puntero a la subcadena. Retorna un puntero a la primera ocurrencia de "cad2" (completa) en "cad1", o un puntero NULL si "cad2" no es parte de "cad1". El proceso de búsqueda y comparación no incluye al caracter de fin de cadena, pero se detiene al llegar al mismo. El siguiente ejemplo busca "simple" dentro de la cadena y lo reemplaza por "propia":
// Ejemplo de uso en C++ #include #include using namespace std; int main () { char str[] ="Esta es una cadena simple"; char * pch; pch = strstr( str, "simple" ); strncpy( pch, "propia", 6 ); cout<
strtok() Divide una cadena en segmentos (o tokens).
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
71
Una secuencia de llamadas a esta función divide "cad" en tokens, que son secuencias de caracteres contíguos separados por cualquiera de los caracteres contenidos en la cadena "delimitantes".
En la primera llamada, la función espera un cstring como argumento para "cad", cuyo primer caracter es utilizado como el punto de partida para buscar tokens. En las llamadas siguientes, la función espera un puntero NULL y utiliza la posición inmediatamente siguiente al fina del último token como nuevo punto de partida para realizar la búsqueda.
Para determinar el principio y el fin de un token, la función primero busca desde la posición inicial la ubicación del primer caracter en "cad" que no está contenido en la cadena "delimitantes" (que se convierte en el principio del token). Y entonces busca, partiendo desde ese principio del token, al primer caracter en "cad" contenido en "delimitantes", que se convierte en el final del token. La búsqueda también se detiene si se llega al caracter de fin de cadena.
Este final del token es automáticamente reemplazado por el caracter de fin de cadena, y el principio del token es retornado como puntero por la función. Una vez que el caracter de fin de cadena en "cad" es encontrado por strtok(), todas las subsecuentes llamadas a esta función (con un puntero NULL como primer argumento) retornarán un puntero NULL. El punto donde el último token fue encontrado se mantiene guardado internamente por la función para ser usado en la siguiente llamada. Valor de retorno: Un puntero al último token encontrado en "cad". Un puntero NULL si no hay más tokens por retirar.
// Ejemplo de uso en C++ #include #include using namespace std; int main () { char cad[] ="- Esta, una cadena de prueba."; char * pch; cout<<"Partiendo la cadena \""<
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
72
OTROS: strerror() Retorna una cadena que describe un error producido en el programa (pura magia). Devuelve un puntero a una cadena que contiene un mensaje sobre un error producido. La función interpreta el valor de errnum, generando una cadena con un mensaje que describe la condición del error como fue descrita en errno por una función de la librería. El puntero retornado apunta a una cadena estática, que no deberá ser modificada por el programa. Subsecuentes llamadas a esta función pueden sobrescribir su contenido. La cadena producida por strerror() puede ser específica para cada sistema e implementaciones de la librería. Valor de retorno: Un puntero a una cadena que describe el error cuyo código representa errnum. Ejemplos de uso // Ejemplo de uso en C++ #include #include #include #include using namespace std; int main () { ifstream flujo( "inexistente.ent" ); if ( !flujo.is_open() ) { cout<<"Error al abrir el archivo unexist.ent: "<
strlen() Retorna el largo de una cadena.
Devuelve el largo de "cadena" (el tipo size_t es como un unsigned int). El largo de la cadena es determinado por el caracter nulo o de fin de cadena (barra invertida cero): una cadena o cstring es tan largo como caracteres haya antes del caracter de fin de cadena (sin incluirlo). Esto no debe confundirse con el tamaño de la cadena como arreglo. Por ejemplo: char micadena[100] = "probando cadena";
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
73
define un arreglo de char con un tamaño de 100 chars, pero la cadena con la cual micadena ha sido inicializada tiene un tamaño de 15 caracteres. Por lo tanto, mientras que sizeof(micadena) devuelve 100, strlen(micadena) retorna 15. Valor de retorno: el largo de la cadena.
Ejemplos de uso: // Ejemplo de uso en C++ #include #include using namespace std; int main () { char entrada[256]; cout<<"Introduzca una frase: "; // El método getline() de cin sirve para leer cadenas con espacios. // sus argumentos son: el arreglo de char donde almacenar la entrada y // el tamaño de dicho arreglo (obtenido con sizeof). cin.getline( entrada, sizeof( entrada ) ); cout<<"La frase ingresada tiene "<
Salida: Introduzca una frase: Hola mundo! La frase ingresada tiene 11 caracteres de largo. Devuelve una cadena de Asteriscos (*) a partir de una frase ingresada #include using namespace std; char *asteriscos(char frase[256]) ; int main() { char frase[]="hola mundo"; cout<
char *asteriscos(char frase[256]) { int i;
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
74
char aux[256]; char ast[0]="*/0"; int l=strlen(frase)+2; for ( i=0; i < l; i++) { aux[i]=ast[0]; } aux[i]= '\0'; return (aux); }
C++ String operator+ // concatenating strings #include #include main () { std::string std::string std::string std::string std::string
firstlevel ("com"); secondlevel ("cplusplus"); scheme ("http://"); hostname; url;
hostname = "www." + secondlevel + '.' + firstlevel; url = scheme + hostname; std::cout << url << '\n'; return 0; }
Output: http://www.cplusplus.com
getline // extract to string #include #include using namespace std; int main () { string name; cout << "Please, enter your full name: "; getline (std::cin,name); cout << "Hello, " << name << "!\n"; return 0; }
Append // agregar
// appending to string
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
75
#include #include using namespace std; int main () { string str; string str2="Writing "; string str3="print 10 and then 5 more"; // used in the same order as described above: str.append(str2); // "Writing " str.append(str3,6,3); // "10 " str.append("dots are cool",5); // "dots " str.append("here: "); // "here: " str.append(10u,'.'); // ".........." str.append(str3.begin()+8,str3.end()); // " and then 5 more" str.append(5,0x2E); // "....." cout << str << '\n'; return 0; }
Assign // asignar // string::assign #include #include int main () { std::string str; std::string base="The quick brown fox jumps over a lazy dog."; // used in the same order as described above: str.assign(base); std::cout << str << '\n'; str.assign(base,10,9); std::cout << str << '\n';
// "brown fox"
str.assign("pangrams are cool",7); std::cout << str << '\n'; // "pangram" str.assign("c-string"); std::cout << str << '\n';
// "c-string"
str.assign(10,'*'); std::cout << str << '\n';
// "**********"
str.assign(10,0x2D); std::cout << str << '\n';
// "----------"
str.assign(base.begin()+16,base.end()-12); std::cout << str << '\n'; // "fox jumps over" return 0; }
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
76
at // string::at #include #include int main () { std::string str ("Test string"); for (unsigned i=0; i
Back//final c++11 // string::back #include #include int main () { std::string str ("hello world."); str.back() = '!'; std::cout << str << '\n'; return 0; }
Begin // string::begin/end #include #include int main () { std::string str ("Test string"); for ( std::string::iterator it=str.begin(); it!=str.end(); ++it) std::cout << *it; std::cout << '\n'; return 0; }
Output: Test string
Capacity / length / size / max_size // comparing size, length, capacity and max_size #include #include int main () { std::string str ("Test string"); std::cout << "size: " << str.size() << "\n"; std::cout << "length: " << str.length() << "\n"; std::cout << "capacity: " << str.capacity() << "\n"; std::cout << "max_size: " << str.max_size() << "\n"; return 0; }
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
77
A possible output for this program could be: size: 11 length: 11 capacity: 15 max_size: 429496729
compare // comparing apples with apples #include #include int main () { std::string str1 ("green apple"); std::string str2 ("red apple"); if (str1.compare(str2) != 0) std::cout << str1 << " is not " << str2 << '\n'; if (str1.compare(6,5,"apple") == 0) std::cout << "still, " << str1 << " is an apple\n"; if (str2.compare(str2.size()-5,5,"apple") == 0) std::cout << "and " << str2 << " is also an apple\n"; if (str1.compare(6,5,str2,4,5) == 0) std::cout << "therefore, both are apples\n"; return 0; }
Output: green apple is not red apple still, green apple is an apple and red apple is also an apple therefore, both are apples
copy // string::copy #include #include int main () { char buffer[20]; std::string str ("Test string..."); std::size_t length = str.copy(buffer,6,5); buffer[length]='\0'; std::cout << "buffer contains: " << buffer << '\n'; return 0; }
Output: buffer contains: string
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
78
c_str // strings and c-strings #include #include #include int main () { std::string str ("Please split this sentence into tokens"); char * cstr = new char [str.length()+1]; std::strcpy (cstr, str.c_str()); // cstr now contains a c-string copy of str char * p = std::strtok (cstr," "); while (p!=0) { std::cout << p << '\n'; p = std::strtok(NULL," "); } delete[] cstr; return 0; }
Output: Please split this sentence into tokens
data // string::data #include #include #include int main () { int length; std::string str = "Test string"; char * cstr = "Test string"; if ( str.length() == std::strlen(cstr) ) { std::cout << "str and cstr have the same length.\n"; if ( memcmp (cstr, str.data(), str.length() ) == 0 ) std::cout << "str and cstr have the same content.\n"; } return 0; }
Output: str and cstr have the same length.
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
79
str and cstr have the same content.
empty // string::empty #include #include int main () { std::string content; std::string line; std::cout << "Please introduce a text. Enter an empty line to finish:\n"; do { getline(std::cin,line); content += line + '\n'; } while (!line.empty()); std::cout << "The text you introduced was:\n" << content; return 0; }
erase // string::erase #include #include int main () { std::string str ("This is an example sentence."); std::cout << str << '\n'; // "This str.erase (10,8); // std::cout << str << '\n'; // "This str.erase (str.begin()+9); // std::cout << str << '\n'; // "This str.erase (str.begin()+5, str.end()-9); // std::cout << str << '\n'; // "This return 0; }
is an example sentence." ^^^^^^^^ is an sentence." ^ is a sentence." ^^^^^ sentence."
Output: This This This This
is an example sentence. is an sentence. is a sentence. sentence.
find // string::find #include #include
// std::cout // std::string
int main () { std::string str ("There are two needles in this haystack with needles."); std::string str2 ("needle"); // different member versions of find in the same order as above: std::size_t found = str.find(str2); if (found!=std::string::npos)
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
80
std::cout << "first 'needle' found at: " << found << '\n'; found=str.find("needles are small",found+1,6); if (found!=std::string::npos) std::cout << "second 'needle' found at: " << found << '\n'; found=str.find("haystack"); if (found!=std::string::npos) std::cout << "'haystack' also found at: " << found << '\n'; found=str.find('.'); if (found!=std::string::npos) std::cout << "Period found at: " << found << '\n'; // let's replace the first needle: str.replace(str.find(str2),str2.length(),"preposition"); std::cout << str << '\n'; return 0; }
Notice how parameter pos is used to search for a second instance of the same search string. Out put: first 'needle' found at: 14 second 'needle' found at: 44 'haystack' also found at: 30 Period found at: 51 There are two prepositions in this haystack with needles.
find_first_not_of // string::find_first_not_of #include // std::cout #include // std::string #include // std::size_t int main () { std::string str ("look for non-alphabetic characters..."); std::size_t found = str.find_first_not_of("abcdefghijklmnopqrstuvwxyz "); if (found!=std::string::npos) { std::cout << "The first non-alphabetic character is " << str[found]; std::cout << " at position " << found << '\n'; } return 0; }
The first non-alphabetic character is - at position 12
find_first_of // string::find_first_of #include // std::cout #include // std::string #include // std::size_t int main () {
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
81
std::string str ("Please, replace the vowels in this sentence by asterisks."); std::size_t found = str.find_first_of("aeiou"); while (found!=std::string::npos) { str[found]='*'; found=str.find_first_of("aeiou",found+1); } std::cout << str << '\n'; return 0; }
Pl**s*, r*pl*c* th* v*w*ls *n th*s s*nt*nc* by *st*r*sks.
find_last_not_of // string::find_last_not_of #include // std::cout #include // std::string #include // std::size_t int main () { std::string str ("Please, erase trailing white-spaces std::string whitespaces (" \t\f\v\n\r");
\n");
std::size_t found = str.find_last_not_of(whitespaces); if (found!=std::string::npos) str.erase(found+1); else str.clear(); // str is all whitespace std::cout << '[' << str << "]\n"; return 0; }
find_last_of // string::find_last_of #include #include #include
// std::cout // std::string // std::size_t
void SplitFilename (const std::string& str) { std::cout << "Splitting: " << str << '\n'; std::size_t found = str.find_last_of("/\\"); std::cout << " path: " << str.substr(0,found) << '\n'; std::cout << " file: " << str.substr(found+1) << '\n'; } int main () { std::string str1 ("/usr/bin/man"); std::string str2 ("c:\\windows\\winhelp.exe"); SplitFilename (str1);
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
82
SplitFilename (str2); return 0; }
Splitting: /usr/bin/man path: /usr/bin file: man Splitting: c:\windows\winhelp.exe path: c:\windows file: winhelp.exe
front // string::front #include #include int main () { std::string str ("test string"); str.front() = 'T'; std::cout << str << '\n'; return 0; }
Output: Test string
insert // inserting into a string #include #include int main () { std::string str="to be question"; std::string str2="the "; std::string str3="or not to be"; std::string::iterator it; // used in the same order as described above: str.insert(6,str2); // to be (the )question str.insert(6,str3,3,4); // to be (not )the question str.insert(10,"that is cool",8); // to be not (that is )the question str.insert(10,"to be "); // to be not (to be )that is the question str.insert(15,1,':'); // to be not to be(:) that is the question it = str.insert(str.begin()+5,','); // to be(,) not to be: that is the question str.insert (str.end(),3,'.'); // to be, not to be: that is the question(...) str.insert (it+2,str3.begin(),str3.begin()+3); // (or ) std::cout << str << '\n'; return 0;
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
83
}
Output: to be, or not to be: that is the question...
length // string::length #include #include int main () { std::string str ("Test string"); std::cout << "The size of str is " << str.length() << " bytes.\n"; return 0; }
Output: The size of str is 11 bytes
operator+= // string::operator+= #include #include int main () { std::string name ("John"); std::string family ("Smith"); name += " K. "; // c-string name += family; // string name += '\n'; // character std::cout << name; return 0; }
Output: John K. Smith
operator= // string assigning #include #include int main () { std::string str1, str2, str3; str1 = "Test string: "; // c-string str2 = 'x'; // single character str3 = str1 + str2; // string std::cout << str3 return 0;
<< '\n';
}
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
84
Output: Test string: x
operator[] // string::operator[] #include #include int main () { std::string str ("Test string"); for (int i=0; i
pop_back // string::pop_back #include #include int main () { std::string str ("hello world!"); str.pop_back(); std::cout << str << '\n'; return 0; }
hello world
push_back // string::push_back #include #include #include int main () { std::string str; std::ifstream file ("test.txt",std::ios::in); if (file) { while (!file.eof()) str.push_back(file.get()); } std::cout << str << '\n'; return 0; }
replace // replacing in a string
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
85
#include #include int main () { std::string std::string std::string std::string
base="this is a test string."; str2="n example"; str3="sample phrase"; str4="useful.";
// replace signatures used in the same order as described above: // Using positions: std::string str=base; str.replace(9,5,str2); str.replace(19,6,str3,7,6); str.replace(8,10,"just a"); str.replace(8,6,"a shorty",7); str.replace(22,1,3,'!');
// // // // // //
0123456789*123456789*12345 "this is a test string." "this is an example string." "this is an example phrase." "this is just a phrase." "this is a short phrase." "this is a short phrase!!!"
// Using iterators: 0123456789*123456789* str.replace(str.begin(),str.end()-3,str3); phrase!!!" (1) str.replace(str.begin(),str.begin()+6,"replace"); phrase!!!" (3) str.replace(str.begin()+8,str.begin()+14,"is coolness",7); cool!!!" (4) str.replace(str.begin()+12,str.end()-4,4,'o'); cooool!!!" (5) str.replace(str.begin()+11,str.end(),str4.begin(),str4.end()); useful." (6) std::cout << str << '\n'; return 0; }
(1) (2) (3) (4) (5)
// "sample // "replace // "replace is // "replace is // "replace is
Output: replace is useful.
reserve // string::reserve #include #include #include int main () { std::string str; std::ifstream file ("test.txt",std::ios::in|std::ios::ate); if (file) { std::ifstream::streampos filesize = file.tellg(); str.reserve(filesize); file.seekg(0); while (!file.eof()) { str += file.get();
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
86
} std::cout << str; } return 0; }
resize // resizing string #include #include int main () { std::string str ("I like to code in C"); std::cout << str << '\n'; unsigned sz = str.size(); str.resize (sz+2,'+'); std::cout << str << '\n'; str.resize (14); std::cout << str << '\n'; return 0; }
Output: I like to code in C I like to code in C++ I like to code
substr
// string::substr #include #include int main () { std::string str="We think in generalities, but we live in details."; // (quoting Alfred N. Whitehead) std::string str2 = str.substr (3,5);
// "think"
std::size_t pos = str.find("live");
// position of "live" in str
std::string str3 = str.substr (pos);
// get from "live" to the end
std::cout << str2 << ' ' << str3 << '\n'; return 0; }
swap // swap strings
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
87
#include #include main () { std::string buyer ("money"); std::string seller ("goods"); std::cout << "Before the swap, buyer has " << buyer; std::cout << " and seller has " << seller << '\n'; seller.swap (buyer); std::cout << " After the swap, buyer has " << buyer; std::cout << " and seller has " << seller << '\n'; return 0; }
Output: Before the swap, buyer has money and seller has goods After the swap, buyer has goods and seller has money
Librería math.h Librería math.h es un archivo de cabecera de la biblioteca estándar . Muchas de sus funciones incluyen el uso de números en coma flotante. Nombre Descripción acos
arcocoseno /* acos example */ #include #include
/* printf */ /* acos */
#define PI 3.14159265 int main () { double param, result; param = 0.5; result = acos (param) * 180.0 / PI; printf ("The arc cosine of %f is %f degrees.\n", param, result); return 0; }
asin atan atan2
arcoseno arcotangente arcotangente de dos parámetros /* atan2 example */ #include
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
/* printf */
88
#include
/* atan2 */
#define PI 3.14159265 int main () { double x, y, result; x = -10.0; y = 10.0; result = atan2 (y,x) * 180 / PI; printf ("The arc tangent for (x=%f, y=%f) is %f degrees\n", x, y, result ); return 0; }
cos abs fmod
coseno valor absoluto resto del punto flotante printf ( "fmod of 5.3 / 2 is %f\n", fmod (5.3,2) ); printf ( "fmod of 18.5 / 4.2 is %f\n", fmod (18.5,4.2) );
Salidas: fmod of 5.3 / 2 is 1.300000 fmod of 18.5 / 4.2 is 1.700000
pow(x,y) sin Sqr
eleva un valor dado a un exponente, xy seno Cuadrado de un número int main () { double param, result; param = 1024.0; result = sqrt (param); printf ("sqrt(%lf) = %lf\n", param, result ); return 0; }
sqrt
raíz cuadrada /* sqrt example */ #include #include
/* printf */ /* sqrt */
int main () { double param, result; param = 1024.0; result = sqrt (param); printf ("sqrt(%f) = %f\n", param, result ); return 0; }
Salida sqrt(1024.000000) = 32.000000
tan
tangente
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
89
Punteros Introducción El puntero es una técnica muy potente que hace que la programación C++ sea tan utilizada. La técnica de punteros apoya a la programación orientada a objetos, que es una de las grandes diferencias entre C y C++. Definición: Un puntero es una variable que almacena una di rección de memoria.
Operador de Dirección: &
Referencias
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
90
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
91
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
92
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
93
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
94
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
95
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
96
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
97
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
98
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
99
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
100
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
101
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
102
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
103
Clases Una clase es la descripción de un tipo de objeto. La descripción abarca la definición de los distintos atributos y métodos inherentes al objeto.
Sintaxis: class tipo_objeto { public: tipo_dato
metodo1 (parámetros);
: tipo_dato private: tipo_dato
metodoN (parámetros); atributo1;
: tipo_dato
atributoN;
}; tipo_dato tipo_objeto::metodo1 (parámetros) { instrucciones; }
:
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
104
tipo_dato tipo_objeto::metodoN (parámetros) { instrucciones; }
En algunos casos se puede pensar en la declaración de atributos en la parte publica y asi mismo el declarar métodos en la parte privada. La parte pública de la clase implica que los elementos definidos en este bloque solo se pueden manipular en cualquier lugar del programa a través de un identificador de acceso (variable o arreglo). La parte privada de la clase implica que los elementos definidos en este bloque solo se pueden manipular solo por métodos definidos en la parte pública.
Constructores. Cuando se crean objetos, una de las operaciones más comunes que se realizan sus programas es inicializar los datos miembros del objeto. Para simplificar el proceso de inicialización de los datos miembros de la clase, el C++ proporciona una función constructora que se ejecuta por si sola cada vez que se crea un objeto. A continuación se presentan las siguientes características de los constructores: Las funciones constructoras son métodos de la clase que facilitan a los programas la inicialización de los datos miembros de la clase.
Las funciones constructoras tienen el mismo nombre que la clase.
Las funciones constructoras no retornan valores.
Cada vez que el programa crea un objeto de la clase, C++ llama a la función constructora de la clase, si
existe. Pueden existir varias funciones constructoras, pero con diferentes parámetros, esto se conoce como sobrecarga.
Destructores. Una función destructora automáticamente se ejecuta cada vez que se finalice la ejecución de un programa. Muchos de los objetos pueden asignar memoria para almacenar información, cuando se descarta a un objeto, el C++ llama a una función destructora especial que puede liberar dicha memoria, limpiando la basura dejada por la desaparición del objeto. A continuación se presentan las siguientes características de los constructores: Las funciones destructoras tienen el mismo nombre que la clase, con la excepción de que debe anteponer a su nombre el carácter tilde (~).
Las funciones destructoras no retornan valores.
Funciones Amigas
Una función amiga de una clase se define por fuera del alcance directo de los miembros privados de dicha clase, pero aún así tiene el derecho de acceso a los miembros private de la clase. Se puede declarar una función o toda una clase como friend de otra clase. Para declarar una función como friend en una clase, en la definición de clase procede el prototipo de la función con la palabra reservada friend.
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
105
Sintaxis: class tipo_objeto { friend tipo_dato funcionamiga (tipo_objeto *, parámetros); public: : private: : }; tipo_dato funcionamiga (tipo_objeto *, parámetros) { instrucciones; }
Ejercicios Resueltos //Programa 1: Procesar información de un empleado por medio de una clase. #include #include class empleado { public: void leer_empleado(void); void mostrar_empleado(void); char nombre[15]; long numero_empleado; float salario; }; void empleado::leer_empleado(void) { cout<< "Nombre:"; cin >> nombre; cout<< "Número:"; cin >> numero_empleado; cout<< "Salario: Bs."; cin >> salario; } void empleado::mostrar_empleado(void) { cout << "Nombre: " << nombre << endl; cout << "Número: " << numero_empleado << endl; cout << "Salario: Bs." << salario << endl; } void main() { empleado trabajador; clrscr(); trabajador.leer_empleado(); cout<<"\nResultado después de la lectura...\n"; trabajador.mostrar_empleado();
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
106
cout<<"\nPresione una Tecla para Continuar"; getch(); }
//Programa 2: Procesar información de cinco empleados por medio de una clase. #include #include class empleado { public: void leer_empleado(void); void mostrar_empleado(void); private: char nombre[15]; long numero_empleado; float salario; }; void empleado::leer_empleado(void) { cout<< "Nombre:"; cin >> nombre; cout<< "Número:"; cin >> numero_empleado; cout<< "Salario: Bs."; cin >> salario; } void empleado::mostrar_empleado(void) { cout<<"\t"<
//Programa 3: Efectuar la asignación y lectura de datos fuera de la clase. #include #include class perros { public:
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
107
char raza[15]; int peso_promedio; int altura_promedio; void mostrar_raza(void); }; void perros::mostrar_raza(void) { cout << "Raza: " << raza << endl; cout << "Peso promedio: " << peso_promedio << endl; cout << "Altura promedio: " << altura_promedio << endl; } void main() { perros canito, canuto; strcpy(canito.raza,"Doberman"); canito.peso_promedio = 58; canito.altura_promedio = 25; cout<<"Ingrese los Datos Referentes a Canuto...\n"; cout<<"Raza:"; cin>>canuto.raza; cout<<"Peso Promedio:"; cin>>canuto.peso_promedio; cout<<"Altura Promedio:"; cin>>canuto.altura_promedio; clrscr(); cout<<"\nResultados después de la lectura...\n\n"; cout<<"Los datos de Canito son:\n"; canito.mostrar_raza(); cout<<"\nLos datos de Canuto son:\n"; canuto.mostrar_raza(); cout<<"\nPresione una Tecla para Continuar"; getch(); }
//Programa 4: Efectuar la lectura y validacion de los miembros de la parte privada de la clase. #include #include class empleado { public: int asignar_valores(char *, long, float); void mostrar_empleado(void); void cambiar_salario(void); private: char nombre[15]; long numero; float salario; }; int empleado::asignar_valores(char *t_nom, long t_num, float t_sal) { strcpy(nombre,t_nom); numero = t_num; if (t_sal > 198000.0 && t_sal < 600000.0) {
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
108
salario = t_sal; return(0); } else
return(-1);
// salario incorrecto // salario equivocado
} void empleado::mostrar_empleado(void) { cout << "Empleado: " << nombre << endl; cout << "Número: " << numero << endl; cout << "Salario: Bs." << salario << endl; } void empleado::cambiar_salario (void) { do { cin>>salario; if (salario < 198000.0 || salario > 600000.0) cout<<"\nSalario Incorrecto...\nDar un nuevo salario:"; } while(salario < 198000.0 || salario > 600000.0); } void main() { empleado trabajador; if (trabajador.asignar_valores("Ana Pérez", 101, 850000.0)== 0) { cout << "Valores asignados al empleado." << endl; trabajador.mostrar_empleado(); } else { cout << "Especifico un salario no válido." << endl; cout << "\nAsigne un nuevo salario:"; trabajador.cambiar_salario(); } cout<<"\nPresione una Tecla para Continuar"; getch(); }
//Programa 5: Efectuar la invocación y lectura de los miembros de la clase, luego //de efectuar la lectura de una clave de seguridad. #include #include #include #define ENTER 13 class empleado { public: void leer_clave(void); void validar_clave(char *); private: void asignar_valores(void); void mostrar_empleado(void); char clave[6]; char nombre[15]; float salario;
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
109
}; void empleado::leer_clave(void) { int j=0; char t_clave[6]; do { t_clave[j]=getch(); if (t_clave[j]!=ENTER) cout<<"*"; j++; } while (t_clave[j-1]!=ENTER); t_clave[j-1]='\0'; validar_clave(t_clave); } void empleado::validar_clave(char *c) { static int i=1; strcpy(clave,"josef"); if (strcmp(c,clave)!=0) { cout<<"\nClave Incorrecta"; if (i==1) { cout<<"\nDar de nuevo la clave:"; i=2; leer_clave(); } else { cout<<"\nHasta Luego...Usuario no Autorizado"; } } else { cout<<"\nClave Correcta"; asignar_valores(); clrscr(); mostrar_empleado(); } } void empleado::asignar_valores(void) { cout<< "\nNombre:"; cin >> nombre; cout<< "Salario: Bs."; cin >> salario; } void empleado::mostrar_empleado(void) { cout << "\nEmpleado: " << nombre << endl; cout << "Salario: Bs." << salario << endl; } void main() { empleado acceso; cout<<"Introduzca clave de acceso (5 caracteres):"; acceso.leer_clave();
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
110
cout<<"\nPresione una Tecla para Continuar"; getch(); }
//Programa 6: Implementación de una función constructora sin parámetros. #include #include // Construccion de la clase tiempo class tiempo { public: tiempo(); void activar_tiempo (int, int, int ); void imprimir_formato_militar (); void imprimir_formato_estandar (); private: int hora; // 0-23 int minuto; // 0-59 int segundo; // 0-59 }; // La funcion tiempo inicializa a 0 los miembros de datos de la clase tiempo::tiempo () { hora=minuto=segundo=0; } // Activa un nuevo tiempo usando el formato militar. Chequea los datos // introducidos, si los datos son invalidos iniciliza los valores de // los miembros de datos en cero. void tiempo::activar_tiempo (int h, int m, int s) { hora = (h >= 0 && h < 24) ? h : 0; minuto = (m >=0 && m < 60) ? m : 0; segundo = (s >=0 && s < 60) ? s : 0; } // Funcion para imprimir el tiempo en formato militar void tiempo::imprimir_formato_militar () { cout<< (hora < 10 ? "0" : "") << hora << ":" << (minuto < 10 ? "0" : "") << minuto << ":" << (segundo < 10 ? "0" : "") << segundo; } // Funcion para imprimir el tiempo en formato estandar void tiempo::imprimir_formato_estandar () { cout << (hora==0 || hora==12 ? 12 : hora%12) << ":" << (minuto < 10 ? "0" : "") << minuto << ":" << (segundo < 10 ? "0" : "") << segundo << (hora < 12 ? " AM" : " PM"); } void main() { clrscr(); tiempo t; // t es una variable objeto de tipo tiempo cout << "El tiempo inicial en formato militar es -> "; t.imprimir_formato_militar ();
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
111
cout << "\nEl tiempo inicial en formato estandar es -> "; t.imprimir_formato_estandar (); t.activar_tiempo (13, 27, 6); cout << "\n\nEl tiempo en formato militar despues de activar un tiempo es -> "; t.imprimir_formato_militar (); cout << "\nEl tiempo en formato estandar despues de activar un tiempo es -> "; t.imprimir_formato_estandar (); t.activar_tiempo (99, 99, 99); cout << "\n\nEl tiempo con datos invalidos:"<< "\nEn formato militar es -> "; t.imprimir_formato_militar (); cout << "\nEn formato estandar es -> "; t.imprimir_formato_estandar (); getch(); }
//Programa 7: Implementación de una función constructora sin parámetros. //Inicialización de un vector numérico a través del constructor. #include #include class entero { public: entero() { x=2; }; void mostrar_valor(void); private: int x; }; void entero::mostrar_valor(void) { cout<
//Programa 8: Implementación de una función constructora con parámetros. #include #include #include class empleado { public: empleado(char *, int, float); void mostrar_empleado(void); private: char nombre[15];
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
112
int numero; float salario; }; empleado::empleado(char *t_nom, int t_num, float t_sal) { strcpy(nombre, t_nom); numero = t_num; salario = (t_sal < 500000.0)? t_sal: 0.0; } void empleado::mostrar_empleado(void) { cout << "\nEmpleado: " << nombre << endl; cout << "Número: " << numero << endl; cout << "Salario: Bs." << salario << endl; } void main() { char nom[15]; float sal; int num; cout<< "Nombre:"; cin >> nom; cout<< "Número:"; cin >> num; cout<< "Salario: Bs."; cin >> sal; empleado trabajador(nom, num, sal); cout<<"\n\nLos datos almacenados después de ejecutarse la función constructora"; trabajador.mostrar_empleado(); cout<<"\nPresione una Tecla para Continuar"; getch(); }
//Programa 9: Sobrecarga de funciones constructoras. #include #include #include class empleado { public: empleado(char *, long, float); empleado(char *, long); void mostrar_empleado(void); int cambiar_salario(float); long leer_numero(void); private: char nombre[25]; long numero_empleado; float salario; }; empleado::empleado(char *nombre, long numero_empleado,float salario) { strcpy(empleado::nombre, nombre); empleado::numero_empleado = numero_empleado; if (salario < 50000.0) empleado::salario = salario; else empleado::salario = 0.0; // salario especificado no válido
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
113
} empleado::empleado(char *nombre, long numero_empleado) { strcpy(empleado::nombre, nombre); empleado::numero_empleado = numero_empleado; do { cout << "Digite un salario para " << nombre << " menor a Pesos. 500,000.00: "; cin >> empleado::salario; } while(salario >= 500000.0); } void empleado::mostrar_empleado(void) { cout << "Empleado: " << nombre << endl; cout << "Número: " << numero_empleado << endl; cout << "Salario: Bs." << salario << endl; } void main() { empleado trabajador("Feliz Guerra", 101, 10101.0); empleado gerente("Juana Pérez", 102); trabajador.mostrar_empleado(); gerente.mostrar_empleado(); cout<<"\nPresione una Tecla para Continuar"; getch(); }
//Programa 10: Implementación de una función destructora. #include #include #include class empleado { public: empleado(char *, int, float); ~empleado(void); void mostrar_empleado(void); private: char nombre[15]; int numero; float salario; }; empleado::empleado(char *t_nom, int t_num, float t_sal) { strcpy(nombre, t_nom); numero = t_num; salario = (t_sal < 500000.0)? t_sal: 0.0; } empleado::~empleado(void) { cout<<"\n\nDestruyendo el objeto para "<< nombre<< endl; getch(); } void empleado::mostrar_empleado(void)
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
114
{ cout << "\nEmpleado: " << nombre << endl; cout << "Número: " << numero << endl; cout << "Salario: Bs." << salario << endl; } void main() { char nom[15]; float sal; int num; cout<< "Nombre:"; cin >> nom; cout<< "Número:"; cin >> num; cout<< "Salario: Bs."; cin >> sal; empleado trabajador(nom, num, sal); cout<<"\n\nLos datos almacenados después de ejecutarse la función constructora"; trabajador.mostrar_empleado(); cout<<"\nPresione una Tecla para Continuar"; getch(); }
//Programa 11: Implementación de una clase cadena para crear y manipular objetos tipo cadenas de caracteres. #include #include #include class cadena { public: cadena(char *); // Constructor void sumar_cadena(char *); void restar_caracter(char); void mostrar_cadena(void); private: char datos[100]; }; cadena::cadena(char *letras) { strcpy(datos, letras); } void cadena::sumar_cadena(char *letras) { strcat(datos, letras); } void cadena::restar_caracter(char letra) { char temp[100]; int i, j; for (i = 0, j = 0; datos[i]; i++) { if (datos[i] != letra) temp[j++] = datos[i]; } temp[j] = NULL; strcpy(datos, temp); }
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
115
void cadena::mostrar_cadena(void) { cout << datos << endl; } void main() { cadena titulo("Aprenda Programación Orientada a Objetos en C++"); cadena tema("Entienda la sobrecarga de operadores"); titulo.mostrar_cadena(); titulo.sumar_cadena(" paso a paso!"); titulo.mostrar_cadena(); tema.mostrar_cadena(); tema.restar_caracter('r'); tema.mostrar_cadena(); cout<<"\nPresione una Tecla para Continuar"; getch(); }
//Programa 12: Implementación de una funcion amiga. #include #include class numero { friend void asignar_valor(numero *,int ); public: numero(){x=0;} void imprimir(void); private: int x; }; void asignar_valor (numero *c,int nx) { c->x=nx; } void numero::imprimir(void) { cout << x << endl; } void main() { int n; numero m; cout<<"El valor de la variable x antes de activar la función amiga: "; m.imprimir(); cout<<"Dar un valor para x:"; cin>>n; asignar_valor(&m,n); cout<<"El valor de la variable x después de activar la función amiga: "; m.imprimir(); cout<<"\nPresione una Tecla para Continuar"; getch(); }
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
116
//Programa 13: Manipulación de una función amiga y variables por referencia. #include #include class entero { friend float suma_condicionada(entero *, int &); public: void cargar(); private: float y; }; void entero::cargar() { cin>>y; } float suma_condicionada(entero *num, int &c) { float x; if (num->y>=100 && num->y<=200) { c++; x=num->y; } else x=0; return x; } void main() { entero vec[100]; float pro, acum=0; char resp; int i=-1,con=0; do { i++; cout<<"Dar valor "<=100); for (int j=0; j<=i; j++) { acum+=(suma_condicionada(&vec[j],con)); } pro=acum/con; printf ("El promedio de los valores condicionados es de:%.2f",pro); cout<<"\nPresione una Tecla para Continuar"; getch(); }
//Programa 14: Implementación de una función amiga dentro de una clase perteneciente a otra clase. #include #include #include
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
117
class libro; class biblioteca { public: void cambiar_catalogo(libro *, char *); }; class libro { public: libro(char *, char *, char *); void mostrar_libro(void); friend void biblioteca::cambiar_catalogo(libro *,char *); private: char titulo[25]; char autor[25]; char catalogo[25]; }; void biblioteca::cambiar_catalogo(libro *este_libro, char *catalogo_nuevo) { strcpy(este_libro->catalogo, catalogo_nuevo); } libro::libro(char *t_titulo, char *t_autor, char *t_catalogo) { strcpy(titulo, t_titulo); strcpy(autor, t_autor); strcpy(catalogo, t_catalogo); } void libro::mostrar_libro(void) { cout << "Título: " << titulo << endl; cout << "Autor: " << autor << endl; cout << "Catálogo: " << catalogo << "\n\n"; } void main() { libro
programacion("Aprenda C++ paso a paso"," Ing. Informatica"," Principiantes"); programacion.mostrar_libro(); biblioteca bibliotecario; bibliotecario.cambiar_catalogo(&programacion,"Como aprender en C++ funciones amigas"); programacion.mostrar_libro(); cout<<"\nPresione una Tecla para Continuar"; getch();
}
Herencia En un material previo se definio la herencia como la habilidad que tiene una clase derivada de heredar las características de una clase base existente. En este material se indicará la manera de cómo programar una herencia simple y múltiple, y una cadena de herencia respectivamente. Herencia Simple
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
118
Sintaxis: class BASE { public: BASE (tipo_dato1,...,tipo_datoN);
: //Otros métodos private: tipo_dato atributo1;
: tipo_dato
atributoN;
}; class DERIVADA: public BASE { public: DERIVADA (tipo_dato1,...,tipo_datoM);
: //Otros métodos private: tipo_dato atributo[N+1];
: tipo_dato
atributoM;
}; DERIVADA::DERIVADA (tipo_dato param1,... ,tipo_dato paramM) :BASE (param1,... ,paramN) //No incluye el tipo de dato { //Asignación de los valores de los pará metros //a los atributos de la clase derivada } //Cuerpo Principal DERIVADA identificador (valor1,...,valorM);
Herencia Múltiple
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
119
Sintaxis: class BASE1 { public: BASE1 (tipo_dato1,...,tipo_datoN);
: //Otros métodos private: tipo_dato atributo1;
: tipo_dato
atributoN;
}; class BASE2 { public: BASE2 (tipo_dato[N+1],...,tipo_datoM);
: //Otros métodos private: tipo_dato atributo[N+1];
: tipo_dato
atributoM;
}; class DERIVADA: public BASE1, public BASE2 { public: DERIVADA (tipo_dato1,...,tipo_datoK);
: //Otros métodos private: tipo_dato atributo[M+1];
: tipo_dato atributoK; }; DERIVADA::DERIVADA (tipo_dato param1,...,tipo_dato paramK) :BASE1 (param1,... ,paramN), BASE2 (param[N+1],... ,paramM) { //Asignación de los valores de los parámetros //a los atributos de la clase derivada }; //Cuerpo Principal DERIVADA identificador (valor1,...,valorK);
E jercicios R esueltos //Programa 1: Herencia simple entre la clase base EMPLEADO y la clase derivada //GERENTE. #include #include #include class empleado { public: empleado(char *, char *, float); void mostrar_empleado(void);
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
120
private: char nombre[15], puesto[15]; float salario; }; class gerente:public empleado { public: gerente(char *, char *, char *, float, float, int); void mostrar_gerente(void); private: float bono; char automovil[15]; int acciones; }; empleado::empleado(char *t_nom, char *t_pue, float t_sal) { strcpy(nombre, t_nom); strcpy(puesto, t_pue); salario = t_sal; } void empleado::mostrar_empleado(void) { cout << "\nNombre: " << nombre << endl; cout << "Puesto: " << puesto << endl; cout << "Salario: Bs." << salario << endl; } gerente::gerente(char *t_nom, char *t_pue, char *t_aut, float t_sal, float t_bono, int t_acc):empleado(t_nom,t_pue,t_sal) { strcpy(automovil, t_aut); bono = t_bono; acciones = t_acc; } void gerente::mostrar_gerente(void) { mostrar_empleado(); cout << "Automóvil de la Empresa: " << automovil << endl; cout << "Bonificacion Anual: Bs." << bono << endl; cout << "Acciones de la Empresa: " << acciones << endl; } void main() { empleado trabajador("Juan Pérez","Programador",850000); gerente jefe("Carmen Gómez","Vicepresidente","Corsa",2500000,30000,500); trabajador.mostrar_empleado(); jefe.mostrar_gerente(); cout<<"\nPresione una Tecla para Continuar"; getch(); }
//Programa 2: Herencia simple entre la clase base LIBRO y la clase derivada //FICHA_PRESTAMO. #include #include #include class libro
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
121
{ public: libro(char *, char *, int); void mostrar_libro(void); private: char titulo[20], autor[20]; int paginas; }; class ficha_prestamo : public libro { public: ficha_prestamo(char *, char *, int, int, int); void mostrar_ficha(void); private: int entrega; // Número de días del préstamo int prestado; // 1 si ha sido prestado, de otra manera 0 }; libro::libro(char *t_tit, char *t_aut, int t_pag) { strcpy(titulo, t_tit); strcpy(autor, t_aut); paginas = t_pag; } void libro::mostrar_libro(void) { cout << "Título: " << titulo << endl; cout << "Autor: " << autor << endl; cout << "Páginas: " << paginas << endl; } ficha_prestamo::ficha_prestamo(char *t_tit, char *t_aut, int t_pag, int t_ent, int t_pre):libro(t_tit, t_aut, t_pag) { entrega = t_ent; prestado = t_pre; } void ficha_prestamo::mostrar_ficha(void) { mostrar_libro(); cout << "Numero de dias del Prestamo: " << entrega << endl; if (prestado) cout << "Estado: No disponible" << endl; else cout << "Estado: Disponible" << endl; } void main() { ficha_prestamo ficha("Herencia en C++","Carmen Cordero",272,3,0); ficha.mostrar_ficha(); cout<<"\nPresione una Tecla para Continuar"; getch(); }
//Programa 3: Herencia simple entre la clase base EMPLEADO y la clase derivada //GERENTE. Uso de la parte protegida en la clase base. #include #include #include
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
122
class empleado { public: void mostrar_empleado(void); protected: char nombre[15], puesto[15]; float salario; }; class gerente:public empleado { public: gerente(char *, char *, char *, float, float, int); void mostrar_gerente(void); private: float bono; char automovil[15]; int acciones; }; void empleado::mostrar_empleado(void) { cout << "Nombre: " << nombre << endl; cout << "Puesto: " << puesto << endl; cout << "Salario: Bs." << salario << endl; } gerente::gerente(char *t_nom, t_bono,int t_acc) { strcpy(nombre, t_nom); strcpy(puesto, t_pue); salario = t_sal; strcpy(automovil, t_aut); bono = t_bono; acciones = t_acc; }
char
*t_pue,
char
*t_aut,
float
t_sal,
float
void gerente::mostrar_gerente(void) { mostrar_empleado(); cout << "Automóvil de la Empresa: " << automovil << endl; cout << "Bonificacion Anual: Bs." << bono << endl; cout << "Acciones de la Empresa: " << acciones << endl; } void main() { gerente jefe("Carmen Gómez","Vicepresidente","Corsa",2500000,30000,500); jefe.mostrar_gerente(); cout<<"\nPresione una Tecla para Continuar"; getch(); }
//Programa 4: Herencia simple entre la clase base LIBRO y la clase derivada //FICHA_PRESTAMO. Uso de la parte protegida en la clase base. #include #include #include class libro { public:
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
123
libro(char *, char *, int); protected: char titulo[20], autor[20]; int paginas; }; class ficha_prestamo : public libro { public: ficha_prestamo(char *, char *, int, int, int); void mostrar_ficha(void); private: int entrega; // Número de días del préstamo int prestado; // 1 si ha sido prestado, de otra manera 0 }; libro::libro(char *t_tit, char *t_aut, int t_pag) { strcpy(titulo, t_tit); strcpy(autor, t_aut); paginas = t_pag; } ficha_prestamo::ficha_prestamo(char *t_tit, char *t_aut, int t_pag, int t_ent, int t_pre):libro(t_tit, t_aut, t_pag) { entrega = t_ent; prestado = t_pre; } void ficha_prestamo::mostrar_ficha(void) { cout << "Título: " << titulo << endl; cout << "Autor: " << autor << endl; cout << "Páginas: " << paginas << endl; cout << "Numero de dias del Prestamo: " << entrega << endl; if (prestado) cout << "Estado: No disponible" << endl; else cout << "Estado: Disponible" << endl; } void main() { ficha_prestamo ficha("Herencia en C++","Carmen Cordero",272,3,0); ficha.mostrar_ficha(); cout<<"\nPresione una Tecla para Continuar"; getch(); }
//Programa 5: Herencia simple entre la clases base EMPLEADO y la clases derivadas //ASALARIADO, POR_HORA y TEMPORAL. #include #include #include class empleado { public: empleado (char *, char *, char *, char *); void mostrar_empleado (void); private: char nombre [20];
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
124
char telefono_casa [20]; char telefono_oficina [20]; char reporta_a [20]; }; class asalariado : public empleado { public: asalariado (char *, char *, char *, char *, float, float, char *); void mostrar_asalariado (void); private: float salario; float nivel_de_primas; char asistente [20]; }; class por_hora : public empleado { public: por_hora (char *, char *, char *, char *,float); void mostrar_por_hora (void); private: float sueldo; }; class temporal : public empleado { public: temporal (char *, char *, char *, char *, float); void mostrar_temporal (void); private: float sueldo; }; empleado::empleado (char *t_nom, char *t_casa, char *t_oficina, char *t_rep) { strcpy (nombre, t_nom); strcpy (telefono_casa, t_casa); strcpy (telefono_oficina, t_oficina); strcpy (reporta_a, t_rep); } void empleado::mostrar_empleado (void) { cout << "Nombre: " << nombre << endl; cout << "Teléfono de casa: " << telefono_casa <
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
125
cout << "Asistente: " << asistente << endl; } por_hora::por_hora (char *t_nom, char *t_casa, char *t_oficina, char *t_rep, float t_sue) : empleado (t_nom, t_casa, t_oficina, t_rep) { sueldo = t_sue; } void por_hora::mostrar_por_hora (void) { mostrar_empleado (); cout << "Sueldo: Bs." << sueldo << endl; } temporal::temporal (char *t_nom, char *t_casa, char *t_oficina, char *t_rep, float t_sue) : empleado (t_nom, t_casa, t_oficina, t_rep) { sueldo = t_sue; } void temporal :: mostrar_temporal (void) { mostrar_empleado ( ); cout << "Sueldo: Bs." << sueldo << endl; } void main (void) { asalariado gerente ("Joel Pérez", "555-1111", "555-1112", "Marco López", 3000000, 10000.0, "Alicia Hernández"); por_hora plomero ("David García", "555-2222", "555-2223", "Marco Sánchez", 45000); temporal recepcionista ("María Flores","555-3333","555-3334","Dora Galván", 40000); gerente.mostrar_asalariado(); cout << endl << endl; plomero.mostrar_por_hora(); cout << endl << endl; recepcionista.mostrar_temporal(); cout<<"\nPresione una Tecla para Continuar"; getch(); }
//Programa 6: Herencia múltiple entre la clases base MONITOR y TARJETA y la clase //derivada COMPUTADORA. #include #include #include class monitor { public: monitor(char *, long, int, int); void mostrar_pantalla(void); private: char tipo[32]; long colores; int resolucion_x; int resolucion_y; }; class tarjeta
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
126
{ public: tarjeta(int, int); void mostrar_tarjeta(void); private: int procesador; int velocidad; }; class computadora : public monitor, public { public: computadora(char *, int, float, char void mostrar_computadora(void); private: char marca[25]; int disco_duro; //Capacidad de float disco_flexible; //Capacidad de };
tarjeta *, long, int, int,int, int);
almacenamiento. almacenamiento.
monitor::monitor(char *t_tipo, long t_col,int x_res, int y_res) { strcpy(tipo, t_tipo); colores = t_col; resolucion_x = x_res; resolucion_y = y_res; } void monitor::mostrar_pantalla(void) { cout << "Tipo de video: " << tipo << endl; cout << "Colores: " << colores << endl; cout << "Resolucion: " << resolucion_x << " por "<< resolucion_y << endl; } tarjeta::tarjeta(int t_pro,int t_vel) { procesador = t_pro; velocidad = t_vel; } void tarjeta::mostrar_tarjeta(void) { cout << "Procesador: " << procesador << endl; cout << "Velocidad: " << velocidad << " Mhz" << endl; } computadora::computadora(char *t_mar, int t_duro, float t_fle, char *t_pan, long t_col,int res_x, int res_y, int t_pro, int t_vel): monitor (t_pan, t_col,res_x, res_y), tarjeta(t_pro, t_vel) { strcpy(marca, t_mar); disco_duro = t_duro; disco_flexible = t_fle; } void computadora::mostrar_computadora(void) { cout << "Marca: " << marca << endl; cout << "Disco Duro: " << disco_duro << " GB" << endl; cout << "Unidad de disquete: " << disco_flexible << " MB" << endl; mostrar_tarjeta(); mostrar_pantalla(); } void main() {
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
127
computadora mipc("Compaq",12,1.44,"VGA",16000000,800,600,586,133); mipc.mostrar_computadora(); cout<<"\nPresione una Tecla para Continuar"; getch(); }
Polimorfismo Mediante las funciones virtuales y el polimorfismo, se hace posible diseñar y poner en práctica sistemas que son de mayor facilidad extensibles. Se pueden escribir programas para procesar objetos de clases existentes y de clases que aun no existan cuando el programa esté en desarrollo. Si esas clases deben ser derivadas de clases base que el programa conozca, éste puede proporcionar un marco general para manipular los objetos de las clases base, y los objetos de las clases derivadas encajarán bien dentro de este marco general. Suponga un conjunto de clases de figuras, como circulo, triángulo, rectángulo y cuadrado, todas ellas derivadas de la clase base figura. En la programación orientada a objetos cada una de estas clases estaría investida con la capacidad de dibujarse a si misma. Aunque cada clase tiene su propia función miembro dibujar, la función dibujar correspondiente a cada figura es bien distinta. Cuando se dibuja una forma, cualquiera que ésta sea, sería agradable tener la capacidad de tratar todas estas formas en una genérica, como objetos de la clase base figura. Entonces al dibujar cualquier figura, solo se llamaría a la función dibujar de la clase base figura, y dejariamos que el programa determinase en forma dinámica (es decir, en tiempo de ejecución) cual de las funciones dibujar de las clases derivadas utilizar. Para habilitar este tipo de comportamiento se declara el método dibujar en la clase base en forma de una función virtual, a continuación, en cada una de las clases derivadas redefinimos dibujar, a fin de que se dibuje la forma apropiada. Se declara una función virtual en la clase base precediendo el prototipo de función con la palabra reservada virtual. Una clase con funciones virtuales se hace abstracta al declarar una o más de sus funciones virtuales como puras. Una función virtual pura es aquella que en su declaración contenga un inicializador de = 0. El polimorfismo es la habilidad que tiene un objeto de cambiar de forma. Si se desglosa el término, descubrirá que el término poli significa “muchos” y morfismo se refiere a “cambios de forma”. Un objeto polimórfico, entonces, es algo que puede tomar muchas formas diferentes. Entre las características más destacadas del polimorfismo se pueden mencionar: El polimorfismo es la habilidad de un objeto de cambiar de forma conforme se establezca en el programa. Para crear objetos polimórficos el programa debe utilizar funciones virtuales. Cualquier clase derivada de una clase base puede utilizar o sobrecargar a una función virtual. Para crear un objeto polimórfico se utiliza un apuntador hacia un objeto de la clase base. Con el polimorfismo existe la capacidad de comportarse de diferentes maneras dependiendo de situaciones que se definen en tiempo de ejecución. En la vida real un objeto puede moverse, eliminarse, repararse y pintarse. Todas las acciones anteriores son genéricas, dependen del objeto sobre el que actúa.
E jercicios Resueltos //Programa 1: Implementación de una función virtual y polimorfismo. #include #include #include class Base {
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
128
public: virtual void f() {cout<<"f(): Clase Base !"<f(); p->g(); p=&d1; p->f(); p->g(); p=&d2; p->f(); p->g(); cout<<"\nPresione una Tecla para Continuar"; getch(); }
//Programa 2: Implementación de funciones virtuales y polimorfismo. #include #include #include class Base { public: virtual void f() {cout<<"f(): Clase Base !"<
EEST N° 5 Amancio Willians Prof. Abdala Achaval Pablo
129
}; class Derivada2: public Derivada1 { public: void f() {cout<<"f(): Clase Derivada2 !"<f(); p->g(); p=&d1; p->f(); p->g(); p=&d2; p->f(); p->g(); cout<<"\nPresione una Tecla para Continuar"; getch(); }