Programaci ´on en C++ para Ciencia e Ingenierıa

Anuncio
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Programación en C++ para Ciencia e
Ingenierı́a
Mario Storti, Lisandro Dalcı́n, Rodrigo Paz
http://www.cimec.org.ar/prog
Facultad de Ingenierı́a y Ciencias Hı́dricas
Universidad Nacional del Litoral http://www.unl.edu.ar
Centro de Investigación de Métodos Computacionales - CIMEC
INTEC, (CONICET-UNL), http://www.cimec.org.ar
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 1
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Autores
• Mario Storti <mario.storti@gmail.>
• Lisandro Dalcı́n, <[email protected]>
• Rodrigo Paz, <[email protected]>
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 2
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Contents
• slide 11.....Elementos básicos de programación
. slide 13.....Compilación vs. intérpretes
. slide 14.....El proceso de compilación
. slide 16.....El preprocesador CPP
. slide 19.....Chequeo de tipos
. slide 20.....Compilación por separado
. slide 22.....Declaraciones y definiciones
. slide 24.....Definiciones y declaraciones de variables
. slide 26.....Incluyendo headers
. slide 29.....Usando librerı́as
. slide 30.....Formato de include para C++
. slide 31.....Un primer programa en C++
. slide 32.....Namespaces
. slide 35.....Estructura de un programa
. slide 37.....Hello world
. slide 38.....Concatenación de arreglos de caracters
. slide 39.....Entrada de datos
. slide 40.....Llamando a otros programas
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 3
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
•
.
.
.
.
.
slide 41.....Strings de C
slide 42.....Strings de C++
slide 44.....Escribir y leer de archivos
slide 46.....La clase vector
slide 49.....Ejercicios
slide 50.....El C en C++
. slide 51.....Funciones
. slide 52.....Valores de retorno
. slide 54.....Usando la librerı́a estándar de C
. slide 55.....Control de ejecución. True and False
. slide 57.....If-else
. slide 61.....while
. slide 64.....do-while
. slide 65.....Lazo for
. slide 66.....Break and continue
. slide 68.....La sentencia switch
. slide 70.....goto
. slide 72.....Recursion
. slide 74.....Operadores
. slide 75.....Operadores de auto incremento
. slide 77.....Tipos de datos
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 4
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
slide 80.....Especificadores
slide 84.....Punteros
slide 94.....Referencias
slide 96.....Punteros a void
slide 98.....Scope de las variables
slide 100.....Definiendo variables on-the-fly
slide 104.....Variables locales
slide 108.....Punteros a variables locales
slide 109.....Variables estáticas
slide 111.....Constantes
slide 112.....Operadores. Asignación
slide 113.....Operadores matemáticos
slide 114.....Operadores relacionales
slide 115.....Operadores lógicos
slide 116.....El operador hook
slide 117.....Errores comunes con los operadores
slide 118.....Operadores de cast
slide 119.....Operador sizeof
slide 120.....typedef: Aliases de tipos
slide 121.....Estructuras
slide 125.....Arrow operator
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 5
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
•
.
.
.
.
.
.
slide 126.....Enum’s
slide 129.....Arreglos de estructuras
slide 130.....Punteros y arreglos
slide 132.....Arreglos de punteros
slide 136.....Aritmética de punteros
slide 138.....Tamaños de estructuras
slide 139.....Programación Orientada a Objetos
. slide 140.....Abstracción de datos
. slide 150.....POO básica
. slide 160.....Inclusion de headers
. slide 164.....Estructuras enlazadas
. slide 172.....Más sobre scoping
. slide 173.....Tipos Abstractos de Datos (ADT)
. slide 174.....Ocultando la implementación
. slide 176.....Control de acceso a los miembros
. slide 180.....Amistad (Friendship)
. slide 183.....Anidamiento (nesting) y amistad
. slide 184.....Object layout
. slide 185.....Clases
. slide 189.....Ocultando totalmente la implementación
. slide 191.....Inicialización y cleanup
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 6
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
•
.
.
.
.
.
.
.
.
.
.
.
.
.
.
slide 193.....El constructor
slide 194.....El destructor
slide 197.....Eliminación del bloque de definición
slide 199.....Clase stash con ctor/dtor
slide 203.....Stack con ctor/dtor
slide 206.....Initialización de agregados
slide 207.....Inicialización de estructuras
slide 208.....Sobrecarga de funciones
slide 212.....Argumentos por default
slide 213.....Constantes
slide 216.....Punteros a arreglos constantes de caracteres
slide 217.....Const en argumentos de funciones
slide 218.....Const en clases
slide 219.....Objetos const y funciones de la clase
slide 221.....Chapter 5
. slide 222.....Funciones inline
. slide 226.....Especificaciones de linkedicion
. slide 228.....Referencias en C++
. slide 234.....Reglas para las referencias
. slide 236.....Paso por referencia y por copia
. slide 237.....El constructor por copia
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 7
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
. slide 238.....Sobrecarga de operadores
. slide 243.....Sobrecarga de operadores unarios
. slide 251.....Sobrecarga de operadores binarios
• slide 273.....Chapter
. slide 274.....Otros operadores que se pueden sobrecargar
. slide 275.....Creación dinámica de objetos
. slide 276.....Uso de la memoria dinámica en C
. slide 277.....Uso de la memoria dinámica en C++
. slide 279.....Porqué usar new y no arreglos
. slide 280.....Memory exhaust
. slide 281.....Composición
. slide 283.....Composición y la cadena de inicialización
. slide 284.....Herencia
. slide 287.....Redefinición de métodos
. slide 289.....Herencia protegida
. slide 291.....Upcasting
. slide 292.....Polimorfismo
. slide 294.....Ejemplo polimorfismo. Integral 1D/2D/3D
. slide 298.....Clase que calcula integral 1D
. slide 300.....Integral 2D. Versión cruda
. slide 315.....Integral 2D. Versión mejorada
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 8
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
•
.
.
.
.
slide 318.....Integral 3D
slide 321.....Integral 1D/2D/3D. User code
slide 323.....Polimorfismo: ej. suma de los elementos de un vector
slide ??.....Ejemplo clase vector sparse
slide 326.....Contenedores de la librerı́a STL
. slide 328.....La librerı́a STL
. slide 328.....La clase vector
. slide 333.....Algoritmos in-place
. slide 335.....La clase list
. slide 338.....La clase set
. slide 342.....La clase map
. slide 345.....Algoritmos
. slide 347.....Programación funcional
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 9
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Dictado
• Docentes de la cátedra:
. Mario Storti <mario.storti@gmail.>
. Lisandro Dalcı́n, <[email protected]>
. Rodrigo Paz, <[email protected]>
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 10
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Elementos básicos de
programación
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 11
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
I KNOW C++!
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 12
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Compilación vs. intérpretes
• Algunos lenguajes de programación tienen un intérprete, por ejemplo
•
•
•
•
Matlab/Octave, Python, Perl, Lisp/Scheme. En un intérprete el usuario va
emitiendo comandos que son interpretados por el intérprete y va
devolviendo un resultado.
Por contraposición, los lenguajes compilados el usuario escribe un
archivo con lı́neas de código, el cuál es procesado por un compilador, que
genera código de máquina, el cual es ejecutado directamente por el
procesador.
Ventajas de la compilación: el código suele ser más rápido, y más
compacto.
Desventajas: el paso de código a ejecutarlo es inmediato, no hay pasos
intermedios. Usualmente los intérpretes permiten escribir tareas que se
repiten comúnmente en archivos de texto (scripts). El usuario puede
además mezclar estas funciones con comandos directamente en el
intérprete. También con los intérprete es más fácil debuggear.
C++ es un lenguaje compilado.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 13
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
El proceso de compilación
• El caso más simple es cuando todo el código del programa está en un
sólo archivo fuente:
1
$$ g++ -o prog prog.cpp
•
Genera un archivo ejecutable prog.
Si el programa es muy grande conviene dividirlo en varias partes, en ese
caso
$$ g++ -o prog prog1.cpp prog2.cpp
• Esto requiere recompilar cada vez todos los *.cpp, si son muchos
1
conviene hacer
1
2
3
$$ g++ -o prog1.o -c prog1.cpp
$$ g++ -o prog2.o -c prog2.cpp
$$ g++ -o prog prog1.o prog2.o
Los archivos .o son objeto, contienen código de máquina. (No tiene
relación con la Programación Orientada a Objetos).
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 14
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
El proceso de compilación (cont.)
• Si solo se modifica uno de los archivos (prog1.cpp), entonces sólo hace
falta recompilar ese.
$$ g++ -o prog1.o -c prog1.cpp
2 $$ g++ -o prog prog1.o prog2.o
• Para mejor organización, si hay muchos *.o conviene ponerlos en una
1
librerı́a
$$ g++ -o prog1.o -c prog1.cpp
2 $$ g++ -o prog2.o -c prog2.cpp
3 $$ g++ -o prog3.o -c prog3.cpp
4 $$ ar r libprog.a prog1.o prog2.o prog3.o
5 $$ g++ -o prog main.cpp libprog.a
• A veces la librerı́a puede ser que haya sido desarrollada por un tercero:
1
libpetsc.a, libmkl.a.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 15
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
El preprocesador CPP
• Muchas veces hay texto que se repite muchas veces en el código. En ese
caso se pueden usar macros
1
2
3
4
int v[100000];
if (n<100000) {
....
}
Se puede simplificar de la siguiente forma
1
2
3
4
5
#define MAX 100000
int v[MAX];
if (n<MAX) {
....
}
Estos macros son manejados por el preprocesador, el cual se llama
normalmente cpp (por C preprocesor). Podemos pensar que el CPP
genera un paso intermedio en el cual toma el archivo prog.cpp y genera
un archivo intermedio tempo.cpp que es el que finalmente es compilado.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 16
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
El preprocesador CPP (cont.)
• CPP sólo realiza manipulaciones a nivel de texto, no conoce nada
especı́fico del lenguaje C/C++, incluso puede usarse (y se usa) para otros
lenguajes como Fortran.
Las directivas más usuales son
•
1 // Incluye todo el texto del archivo library.h
2 #include <library.h>
3
4 #define CHECK(a,n) if (a>n) error()
• Para #include el preprocesador simplemente incluye todo el archivo
•
•
mencionado en el punto donde se invoca el include.
#define define un macro, después se puede llamar al macro en otros
lugares del código y es reemplazado por su expansión. Los macros
pueden tener argumentos. Por convención se suele dar a los macros
nombres en mayúsculas.
Se puede conocer cual es el resultado del CPP llamando a g++ con la
opción -E
$$ g++ -o tempo.cpp -E prog.cpp
• El CPP es un programa separado que se puede llamar por sı́ mismo
1
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 17
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
(/usr/bin/cpp).
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 18
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Chequeo de tipos
• C++ es un lenguaje tipado (aka tipeo estático, en inglés typed language),
es decir las variables tienen tipos definidos. El compilador chequea que
los resultados de las expresiones que se asignan a las variables
correspondan al tipo con el cual fueron definidas, caso contrario se
produce un error en tiempo de compilación. Esto es bueno porque
permite detectar tempranamente errores. (Es equivalente al chequeo de
unidades en Fı́sica).
// error: asigna un string a una variable entera
2 int a;
3 a = "Hello";
• Otros lenguajes (sobre todos los interpretados) hacen chequeo dinámico
1
de tipo, esto implica una pérdida de eficiencia.
El chequeo se hace también para los argumentos de una función
•
1 void fun(int a,string s);
2 . . .
3 fun(23,45); // ERROR (45 no es un string!)
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 19
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Compilación por separado
• En C++ se favorece que un programa grande se pueda dividir en
•
fracciones más pequeñas. El mecanismo fundamental para dividir un
programa en partes más pequeñas es usar funciones que realizan tareas
bien definidas. Por ejemplo podemos pensar en una función int
gcd(int,int); que toma dos enteros y retorna el máximo común divisor
de los mismos.
Las funciones tienen argumentos, una vez que la función termina su
tarea, retorna un valor. También puede ser que las funciones tengan
efectos colaterales (side effects) es decir que modifiquen sus
argumentos u otros objetos.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 20
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Compilación por separado (cont.)
• Para crear un programa que esté dividido en varios archivos, el código de
un archivo debe poder usar las funciones del otro. Supongamos que un
archivo prog1.cpp contiene a la función gcd(). Si queremos usar a gcd()
en el código de otro archivo prog2.cpp entonces el compilador debe estar
seguro que el tipo de los argumentos que se le van a pasar son los
correctos. Para eso hay que declarar a la función en prog2.cpp antes de
poder llamarla
1
2
3
4
int gcd(int,int); // declara gcd()
...
r = gcd(m,n); // la puede usar porque ya
// fue declarada
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 21
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Declaraciones y definiciones
• Una declaración le dice al compilador que esa función existe y su
prototipo o signatura, es decir el tipo de argumentos de entrada y de
salida. Por ejemplo
int gcd(int,int);
• La definición por otra parte dice especı́ficamente como la función realiza
1
su tarea
1
2
3
4
5
6
7
8
9
10
11
int gcd(int x, int y) {
int a = x, b = y;
if (b>a) {
a = y; b = x;
}
while (true) {
int c = a % b;
if (c==0) return b;
a = b; b = c;
}
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 22
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Declaraciones y definiciones (cont.)
• Cada función puede estar declarada varias veces en un archivo (mientras
la signatura de la función sea la misma en cada una de las declaraciones).
int f(int x);
...
3 int f(int); // OK, misma signatura
• Por el contrario, la función sólo puede estar definida una sola vez en todos
1
2
los archivos del programa, ya que si no el compilador no sabrı́a cual usar.
1
2
3
4
5
6
// archivo prog1.cpp
int f(int x) { return 2*x; }
// archivo prog2.cpp
int f(int x) { return 3*x; }
// -> ERROR: múltiplemente definida
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 23
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Definiciones y declaraciones de variables
Si declaramos una variable, por ejemplo
1
int m;
si bien parace una declaración, en realidad ya tiene toda la información para
construir al objeto (un entero de 4 bytes) por lo tanto el compilador lo toma
además como una definición. Por eso no podemos incluir dos veces esta
declaración/definición, aunque sea del mismo tipo.
1
2
3
int m;
...
int m; // ERROR
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 24
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Definiciones y declaraciones de variables (cont.)
• Si queremos forzar a que sea una declaración y no una definición
entonces debemos usar el keyword extern
extern int m;
...
3 extern int m; // OK
4 . . .
5 int m; // OK
• extern se puede usar también con las funciones, para hacer hincapié en
1
2
que es una declaración, por ejemplo
1
extern int f(int x);
pero no es necesario.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 25
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Incluyendo headers
• Es usual que en nuestros programas escribamos una serie de funciones
que después utilizaremos en otras partes del programa.
// utils.cpp
2 int gcd(int m,int n) { /* . . . */ }
3 double cos(double alpha) { /* . . . */ }
4 double sin(double alpha) { /* . . . */ }
5 . . .
• Cuando queremos usar estas funciones en otro archivo fuente prog.cpp
1
primero tenemos que declararlas
1
2
3
4
5
6
7
8
9
// prog.cpp
int gcd(int m,int n);
double cos(double alpha);
double sin(double alpha);
...
int x = gcd(m,n);
double c = cos(alpha);
double s = sin(theta);
...
Esto se vuelve muy engorroso si hay que incluir las declaraciones en cada
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 26
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
uno de los archivos prog1.cpp, prog2.cpp... y utils.cpp tiene cientos de
funciones. Entonces para resolver esto incluimos todas las declaraciones
en un archivo header (cabecera) utils.h:
1
2
3
4
// utils.h
int gcd(int m,int n);
double cos(double alpha);
double sin(double alpha);
Entonces después en prog1.cpp hay que solo incluir el header:
1
2
3
4
5
6
7
// prog1.cpp
#include "utils.h"
...
int x = gcd(m,n);
double c = cos(alpha);
double s = sin(theta);
...
Recordemos que lo que ocurre es que el preprocesador CPP se encarga
de buscar el archivo header y crear un archivo temporario donde la linea
del include es reemplazada por los contenidos del archivo.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 27
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Incluyendo headers (cont.)
Hay dos versiones de include,
• Una que especifica archivos en forma relativa o absoluta
1 #include ". ./utils.h"
2 #include "utils2.h"
3 #include "/usr/include/utils3.h"
4 . . .
• Otra que busca los headers en una serie de directorios que el usuario
define en el comando de compilación
1
1
2
3
4
5
$$ g++ -I/home/mstorti/utils -c -o prog.o prog.cpp
// lo encuentra en /home/mstorti/utils
#include <utils4.h>
// lo encuentra en /home/mstorti/utils/src
#include <src/utils5.h>
...
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 28
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Usando librerı́as
• Entonces si tengo que usar una librerı́a matrix que está compuesta de
varios archivos fuente matrix2.cpp, matrix1.cpp, matrix3.cpp... en realidad
no hace falta que compile todos estos archivos, mientras que el
desarrollador de esa librerı́a provea
. Un archivo libmatrix.a con todos los matrix<n>.cpp compilados.
. Un archivo header con las declaraciones de las funciones matrix.h.
Entonces para usar la librerı́a basta con incluir el header
•
1 // myprog.cpp
2 #include <matrix.h>
3 . . .
y al linkeditar incluir la librerı́a
1
$$ g++ myprog.cpp /usr/lib/libmatrix.a -o myprog
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 29
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Formato de include para C++
• La extensión que se usa para los archivos fuente puede ser .cpp, .cxx.
•
Para los headers se utiliza .h, .hpp, .hxx.
Para evitar confusiones y ambigüedad con las extensiones, C++ introdujo
el concepto de include sin extensión. El traductor se encarga de convertir
el nombre y buscar la extensión.
#include <matrix>
• Existe una librerı́a con muchas funciones muy útiles que es estándar de C
1
y se llama justamente libc.a. Entre otras incluye funciones
. Matemáticas math.h: round, cos, sin, floor, ceil, ...
. Input/output stdio.h: printf, scanf, read, write,
. stdlib.h: rand, system, ...
En C++ estos headers es mejor incluirlos sin el .h y con una c:
1
2
#include <stdio.h> // C
#include <cstdio> // C++
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 30
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Un primer programa en C++
• Para imprimir por terminal hay que usar el operador << de la clase
iostream:
1
2
3
#include <iostream>
...
cout << "Hola";
El operador << en C quiere decir en realidad otra cosa: es para desplazar
los bits en un número entero. Pero C++ permite redefinir los operadores
(lo que se llama sobrecarga de operadores) de manera que en este
contexto << quiere decir “enviar a”.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 31
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Namespaces
• A medida que una librerı́a o programa crecen cada vez hay más funciones
•
y es muy posible que se produzca la colisión de nombres. Por ejemplo, si
escribo una librerı́a para manipular matrices, puedo querer implementar
una función rand() que llena la matriz con números aleatorios.
Lamentablemente la libc ya usa el nombre rand() para generar un único
numero aleatorio.
Una solución que se usaba en C era prependizar un prefijo identificador
de la librerı́a a todas las funciones de la misma matrix_rand(),
matrix_sum(), matrix_prod(). Esto se vuelve muy engorroso.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 32
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Namespaces (cont.)
• C++ provee un mecanismo para evitar colisiones llamado namespaces.
Todos los archivos de la librerı́a se incluyen en un namespace de la
siguiente forma
// matrix.cpp
2 namespace matrix {
3
void rand(. . .) { /* . . . */ }
4
double sum(. . .) { /* . . . */ }
5
void prod(. . .) { /* . . . */ }
6 }
• Entonces después las funciones se deben llamar con el operador de
1
•
1
2
3
4
5
scope ::: por ejemplo matrix::rand().
Si en un archivo fuente se va a utilizar mucho una librerı́a entonces puede
incluir todo el namespace, de manera que no hay que hacer el scope
// prog.cpp
using namespace matrix;
rand(A);
double m = max(A);
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 33
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Namespaces (cont.)
• Muchas utilidades y variables estándar de C++, por ejemplo cout, están en
el namespace std de manera que o bien hay que hacer
1
std::cout << "Hola";
o si no
1
2
3
using namespace std;
...
cout << "Hola";
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 34
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Estructura de un programa
• Un programa en C/C++ está compuesto de una colección de funciones y
•
variables. Cuando uno lanza el programa hay que determinar dónde se
empieza a ejecutar el código, o sea el punto de entrada. En C/C++ el punto
de entrada es la función main().
La definición de una función consiste en un valor de retorno, el nombre
de la función y su lista de argumentos. El cuerpo de la función (las
instrucciones que la componen) van entre llaves.
int function() {
2
// Function code here (this is a comment)
3 }
• Puede haber más pares de llaves balanceadas ({}) adentro de la función
1
•
pero debe haber uno más externo que define el cuerpo de la función.
Como main() es una función, debe respetar estos requisitos. main() no
tiene argumentos y retorna un int.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 35
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Estructura de un programa (cont.)
• C/C++ es un lenguaje de formato libre (free form), la indentación o la
•
•
1
2
3
posición de las variables en la lı́nea son irrelevantes.
Tampoco es relevante la cantidad espacio en blanco (espacios, tabs, fin
de lı́nea). Cualquier cantidad de estos caracteres juntos es equivalente a
un solo espacio. De hecho un programa en C++ podrı́a escribirse ne una
sola lı́nea.
En C los comentarios van encerrados entre /* y */ (comentario multilı́nea).
En C++ se agregó un nuevo tipo de comentario que es por lı́nea desde un
// hasta el final de la lı́nea. (Esto viola un poco el concepto de free form).
/* Comentario multilinea tipo C */
int /* comentario en el medio del código */ x;
// Comentario por linea tipo C++
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 36
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Hello world
1
2
3
4
5
6
7
8
// Saying Hello with C++
#include <iostream> // Stream declarations
using namespace std;
int main() {
cout << "Hello, World. I am "
<< 8 << " Today" << endl;
}
• Le pasamos a cout una serie de elementos de diferentes tipos: enteros,
•
•
•
arreglos de caracteres.
endl es un final de lı́nea.
En C se llama string a un pedazo de texto entre comillas. No confundir
con la clase string de C++ que cumple funciones similares pero es mucho
más potente. A los strings de C se los debe llamar más correctamente
arreglos de caracteres.
Dentro del texto entre comillas se pueden incluir secuencias de escape
que permiten incluir caracteres especiales con precedidos de una barra
invertida: \n es un caracter de fin de lı́nea, \t un TAB, \0 un NULL, \\ una
barra invertida.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 37
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Concatenación de arreglos de caracters
• Para incluir arreglos de caracteres muy largos se puede simplemente
poner uno a continuación de otro (puede ser en diferentes lı́neas). El CPP
se encarga de juntarlos todos en una sola lı́nea: "aaa" "bbbb" es
completamente equivalente a "aaabbbb".
1
2
3
4
5
6
7
8
9
10
11
// Character array Concatenation
#include <iostream>
using namespace std;
int main() {
cout << "This is far too long to put on a "
"single line but it can be broken up with "
"no ill effects\nas long as there is no "
"punctuation separating adjacent character "
"arrays.\n";
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 38
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Entrada de datos
cout es console output, cin es console input y permite ingresar datos.
1
2
3
4
5
6
7
8
9
10
11
12
13
// Converts decimal to octal and hex
#include <iostream>
using namespace std;
int main() {
int number;
cout << "Enter a decimal number: ";
cin >> number;
cout << "value in octal = 0"
<< oct << number << endl;
cout << "value in hex = 0x"
<< hex << number << endl;
}
oct y hex son manipulators, cambian el estado de cout.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 39
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Llamando a otros programas
Dentro de la librerı́a estándar de C hay una función muy potente system() que
permite llamar a otros programas desde un programa en C/C++. Se le pasa un
arreglo de caracteres con el comando que uno ejecutarı́a en la lı́nea de
comandos.
1
2
3
4
5
6
7
// Call another program
#include <cstdlib> // Declare ‘‘system()’’
using namespace std;
int main() {
system("date -u");
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 40
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Strings de C
Manipular arreglos de caracteres en C se vuelve muy engorroso.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <cstring>
using namespace std;
int main() {
// concatenate two character arrays s1 and s2
char s1[ ] = "Hola ";
char s2[ ] = "mundo.";
cout << strlen(s1) << endl;
int n1 = strlen(s1);
int n2 = strlen(s2);
char *s = new char[n1+n2+1];
strncpy(s,s1,n1);
strncpy(s+n1,s2,n2);
s[n1+n2] = ’\0’;
cout << s << endl;
delete[ ] s;
return 0;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 41
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Strings de C++
Para eso C++ tiene objetos llamados strings que permiten manipularlos en
forma mucho más simple y con menor probabilidad de error.
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <string>
using namespace std;
int main() {
// concatenate two character arrays s1 and s2
string s1 = "Hola ";
string s2 = "mundo.";
string s = s1 + s2;
cout << s << endl;
return 0;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 42
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Strings de C++ (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//: C02:HelloStrings.cpp
// The basics of the Standard C++ string class
#include <string>
#include <iostream>
using namespace std;
int main() {
string s1, s2; // Empty strings
string s3 = "Hello, World."; // Initialized
string s4("I am"); // Also initialized
s2 = "Today"; // Assigning to a string
s1 = s3 + " " + s4; // Combining strings
s1 += " 8 "; // Appending to a string
cout << s1 + s2 + "." << endl;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 43
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Escribir y leer de archivos
•
•
•
•
1
2
3
4
5
6
7
8
9
10
11
Las funciones están declaradas en el header <fstream>.
Para escritura hay que crear un objeto de tipo ofstream (como cout).
Para lectura hay que crear un objeto de tipo ifstream (como cin).
La función getline(stream,s) lee una lı́nea de stream y la guarda en el
string s
// Copy one file to another, a line at a time
#include <string>
#include <fstream>
using namespace std;
int main() {
ifstream in("Scopy.cpp"); // Open for reading
ofstream out("Scopy2.cpp"); // Open for writing
string s;
while(getline(in, s)) // Discards newline char
out << s << "\n"; // . . . must add it back
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 44
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Escribir y leer de archivos (cont.)
Otro ejemplo es guardar todo el archivo en un sólo string:
1
2
3
4
5
6
7
8
9
10
11
12
13
// Read an entire file into a single string
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
int main() {
ifstream in("FillString.cpp");
string s, line;
while(getline(in, line))
s += line + "\n";
cout << s;
}
¿Que pasa si queremos guardar cada lı́nea en un string separado?
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 45
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
La clase vector
• Un vector es un contenedor que permite guardar un número indefinido de
•
•
•
elementos en forma contigua e indexada.
Se puede agrandar o achicar en forma dinámica, sin perder los elementos
preexistentes.
Está templatizado o sea que se pueden definir vectores de diferentes
tipos: vector<int>, vector<double>, vector<string>,...
La función push_back() permite agregar un nuevo objeto al final del vector.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 46
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
La clase vector (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Copy an entire file into a vector of string
#include <string>
#include <iostream>
#include <fstream>
#include <vector>
using namespace std;
int main() {
vector<string> v;
ifstream in("Fillvector.cpp");
string line;
while(getline(in, line))
v.push-back(line); // Add the line to the end
// Add line numbers:
for(int i = 0; i < v.size(); i++)
cout << i << ": " << v[i] << endl;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 47
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
La clase vector (cont.)
vector también puede guardar cualquier otro tipo, por ejemplo enteros:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Creating a vector that holds integers
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v;
for(int i = 0; i < 10; i++)
v.push-back(i);
for(int i = 0; i < v.size(); i++)
cout << v[i] << ", ";
cout << endl;
for(int i = 0; i < v.size(); i++)
v[i] = v[i] * 10; // Assignment
for(int i = 0; i < v.size(); i++)
cout << v[i] << ", ";
cout << endl;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 48
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Ejercicios
1. Crear un programa que abre un archivo y cuenta las palabras (separadas
por whitespace). Ayuda: el operador >> lee de a palabras de un ifstream.
2. Crear un programa que cuenta la cantidad de caracteres que tiene un
archivo.
3. Crear un programa que cuenta la cantidad de ocurrencias de una palabra
especı́fica en un archivo. Ayuda: usar == para comparar strings.
4. Escribir un programa que imprime las lı́neas de un archivo de texto en
orden inverso.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 49
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
El C en C++
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 50
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Funciones
• Para evitar errores, C/C++ usa el concepto de prototipo o signatura de
•
•
funciones.
Antes de usar una función hay que declararla.
Al usar la función los argumentos con que es llamada deben coincidir con
el el tipo que fueron declarados.
int translate(float x, float y, float z);
2 int translate(float, float, float);
• En algún lugar la función tiene que estar definida, aquı́ los nombres de los
1
argumentos tienen que aparecer para poder ser usados en la función
1
2
3
4
int translate(float x, float y, float z) {
x = y = z;
// . . .
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 51
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Valores de retorno
• La declaración de la función debe indicar el valor de retorno. Si la función
no retorna nada usar void:
int f1(void); // Returns an int, takes no arguments
2 int f2(); // Like f1() in C++ but not in Standard C
3 float f3(float, int, char, double); // Returns a float
4 void f4(void); // Takes no arguments, returns nothing
• Para retornar el valor usar la sentencia return.
• Si la función retorna void entonces no se debe llamar a return.
• Se puede tener más de un return en la función. Son puntos de salida.
• El valor de retorno debe ser compatible con el indicado en la declaración.
1
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 52
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Valores de retorno (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Use of ‘‘return’’
#include <iostream>
using namespace std;
char cfunc(int i) {
if(i == 0)
return ’a’;
if(i == 1)
return ’g’;
if(i == 5)
return ’z’;
return ’c’;
}
int main() {
cout << "type an integer: ";
int val;
cin >> val;
cout << cfunc(val) << endl;
} ///:˜
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 53
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Usando la librerı́a estándar de C
• C incluye una librerı́a de funciones estándar (también llamada libc). Todos
•
•
•
los compiladores que satisfacen la norma deben incluir estas funciones
en su libc. Esto permite la portabilidad de los programas entre diferentes
compiladores.
Muchos compiladores incluyen funciones adicionales que NO están en la
norma. Por lo tanto hay que prever que si se lleva el proyecto a otra
plataforma puede ser que estas funciones no existan en esa plataforma.
La documentación de las librerı́as usualmente incluye la declaración de la
función y en que header (archivo .h) está.
En caso que la librerı́a no esté documentada hay que directamente ver los
headers para encontrarel prototipo de la función.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 54
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Control de ejecución. True and False
• Todas los condicionales (por ejemplo if o while) usan expresiones lógicas
•
1
2
3
4
5
6
como por ejemplo el resultado del operador de comparación A==B. Esta
expresión retorna directamente un valor lógico true o false. No confundiir
con el operador de asignación A=B.
Lo mismo ocurre con otros operadores de comparación
A==B; //It’s equal?
A!=B; //It’s distinct?
A<B; //It’s smaller?
A<=B; //It’s smaller or equal?
A>B; //It’s greater?
A>=B; //It’s greater or equal?
Si la expresión no retorna un valor booleano, entonces C trata de convertirlo.
Para todos los valores numéricos (enteros, float, double, char, punteros) el
valor es falso si es cero, y en cualquier otra caso es verdadero. Entonces por
ejemplo el valor lógico de las siguientes expresiones es equivalente
1
2
if (n) { . . . }
if (n!=0) { . . . . }
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 55
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
3
if (!(n==0)) { . . . . } // ! is negation
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 56
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
If-else
El if puede existir de dos formas, con o sin else
1
2
3
4
5
6
7
8
9
if (expression)
statement
// o
if (expression)
statement
else
statement
En ambos casos statement puede ser una sentencia simple, terminada en una
coma, o compuesta, es decir un bloque de instrucciones encerrado en {}.
1
2
3
4
5
6
if (n>0) x=23; // sentencia simple
if (n>0) { // sentencia compuesta
x=23;
s="haha";
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 57
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
If-else (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
int i;
cout << "type a number and ’Enter’" << endl;
cin >> i;
if(i > 5)
cout << "It’s greater than 5" << endl;
else
if(i < 5)
cout << "It’s less than 5 " << endl;
else
cout << "It’s equal to 5 " << endl;
cout << "type a number and ’Enter’" << endl;
cin >> i;
if(i < 10)
if(i > 5) // ‘‘if’’ is just another statement
cout << "5 < i < 10" << endl;
else
cout << "i <= 5" << endl;
else // Matches ‘‘if(i < 10)’’
cout << "i >= 10" << endl;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 58
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
If-else (cont.)
Notar que todo el if actúa como una sola instrucción, por eso no hace falta
encerrarlo con un {}.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if(i > 5)
cout << "It’s greater than 5" << endl;
else
if(i < 5)
cout << "It’s less than 5 " << endl;
else
cout << "It’s equal to 5 " << endl;
// es equivalente a
if(i > 5) { cout << "It’s greater than 5" << endl; }
else {
if(i < 5)
cout << "It’s less than 5 " << endl;
else
cout << "It’s equal to 5 " << endl;
}
Es una convención mut útil indentar ambos bloques del if para mejorar la
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 59
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
legibilidad.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 60
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
while
while, do-while y for controlan lazos (loops) de ejecución.
1
2
while(expression)
statement
Como antes statement puede ser simple o compuesto. La expresión se evalúa
hasta que la condición de falso. Para que el lazo termine en algún momento
es necesario que statement tenga algún efecto que haga que eventualmente
expression de falso
1
2
3
4
5
6
7
int x=0;
while (x<5) x=34; // ejecuta una vez el lazo
x=0;
while (x<5) x=2; // ejecuta indefinidamente
x=0;
while (x<5) x++; // ejecuta el bloque 5 veces
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 61
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
while (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Guess a number (demonstrates ‘‘while’’)
#include <iostream>
using namespace std;
int main() {
int secret = 15;
int guess = 0;
// != is the not-equal conditional:
while(guess != secret) { // Compound statement
cout << "guess the number: ";
cin >> guess;
}
cout << "You guessed it!" << endl;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 62
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
while (cont.)
En C la condición dentro del condicional puede ser tan elaborada como se
quiera, la única restricción es que debe retornar un valor lógico (o convertible
a lógico), incluso puede ser que el cuerpo del lazo este vacı́o
1
2
while(do-a-lot-of-work()) ;
while(do-a-lot-of-work()) { }
por ejemplo
1
while(is-prime(n)) n++; // busca el primer n no primo
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 63
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
do-while
1
2
3
do
statement
while(expression);
Es similar al while pero ahora statement es ejecutado antes de verificar la
condición.
1
2
3
4
5
6
7
n=0;
while (n>0) /* body. . .*/ ; // body is not executed
n=0;
do
/* body. . .*/ ; // body is executed once
while (n>0);
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 64
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Lazo for
La forma del for es
1
2
for(initialization; conditional; step)
statement
Se utiliza mucho cuando simplemente se quiere ejecutar un bloque una serie
de veces bien definida
1
2
3
for (int i=0; i<n; i++) {
// This block is executed n times
}
Esto es completamente equivalente a
1
2
3
4
5
int i=0;
while(i<n) {
// This block is executed n times
i++;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 65
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Break and continue
Adentro de cualquiera de los bloques while, do-while o for se puede usar
break para salir del lazo inmediatamente.
1
2
3
4
5
6
while (true) { // Infinite loop
cout << "Enter a number: ";
cin >> n;
if (is-prime(n)) break;
cout << n << " es un número compuesto" << endl;
}
Si hay más de un lazo anidado entonces break sale del lazo más interno
1
2
3
4
5
6
7
for (int i=0; i<n; i++) {
for (int j=0; j<n; j++) {
if (j>i*i) break;
//. . .
}
// break transfers execution here
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 66
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Break and continue (cont.)
continue es similar a break pero hace que se ejecute la siguiente iteración del
lazo
1
2
3
4
5
for (int j=0; j<n; j++) {
//. . . .
if (!is-prime(j)) continue;
// do this only for primes. . .
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 67
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
La sentencia switch
Va comparando la variable selector hasta que coincide con uno de los case
1
2
3
4
5
6
7
8
9
switch(selector) {
case integral-value1
case integral-value2
case integral-value3
case integral-value4
case integral-value5
(. . .)
default: statement;
}
:
:
:
:
:
statement;
statement;
statement;
statement;
statement;
break;
break;
break;
break;
break;
por ejemplo
1
2
3
4
5
6
7
char c;
//. . .
switch (c) {
case ’a’: cout << "It’s an a" << endl; break;
case ’b’: cout << "It’s a b" << endl; break;
default: cout << "Neither a or b" << endl;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 68
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Si no se incluyen los break entonces la ejecución sigue al siguiente case.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 69
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
goto
La sentencia goto permite saltar a otro punto del programa. Se lo considera
muchas veces como una mala práctica de programación, aunque a veces
puede ser útil, por ejemplo para saltar de varios lazos anidados cuando se
encuentra una condición.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// The infamous goto is supported in C++
#include <iostream>
using namespace std;
int main() {
long val = 0;
for(int i = 1; i < 1000; i++) {
for(int j = 1; j < 100; j += 10) {
val = i * j;
if(val > 47000)
goto bottom;
// Break would only go to the outer ’for’
}
}
bottom: // A label
cout << val << endl;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 70
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
17
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 71
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Recursion
Muchos problemas son intrı́nsecamente recursivos, es decir la solución de un
problema está dada por la solución de uno menor con el mismo algoritmo,
por ejemplo la definición de factorial se puede hacer en forma recursiva
n! = n · (n − 1)!
(1)
en realidad esto es cierto si n
> 1, la definición correcta es

1;
si n = 1;
n! =
n · (n − 1)! ; si n > 1
decimos que el caso n
(2)
= 1 corta la recursión.
Usando llamadas recursivas a funciones podemos implementar la función
factorial
1
2
3
4
int factorial(int n) {
if (n==1) return 1;
else return n*factorial(n-1);
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 72
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Recursion (cont.)
La recursión es muy elegante para resolver problemas, pero puede ser
demandante en términos de recursos. Es más simple si calculamos el
factorial con un lazo
1
2
3
4
5
int factorial(int n) {
int fac=1;
for (int j=2; j<=n; j++) fac *= j;
return fac;
}
El operador *= quiere decir aquı́
1
fac = fac*j;
Se puede aplicar a otros operadores binarios como +*-/, operadores lógicos
||&&, concatenación de strings...
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 73
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Operadores
Los operadores no son más que funciones, con una sintaxis especial. Un
operador toma una o más series de valores y devuelve un resultado.
1
a = b + c;
podemos pensar que es traducido por el compilador en
1
a = sum(b,c);
Una cuestión importante con los operadores es la precedencia de los
mismos. Para los operadores matemáticos es similar a las reglas que
aprendemos en la escuela
1
a = b * c + d;
es equivalente a
1
a = (b * c) + d;
porque * tiene mayor precedencia que +. Ante la duda, se pueden introducir
paréntesis para forzar el orden en que se evalúan las expresiones.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 74
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Operadores de auto incremento
El operador ++ es un atajo para una operación muy común en programación:
incrementar una variable de tipo entero en una unidad. Hay dos variantes,
prefija y postfija, ambos tienen el mismo efecto colateral (incrementar la
variable) pero en el prefijo retorna el valor de la variable incrementada, y el
postfijo sin incrementar
1
2
3
4
5
int m,n=5;
m = n++; // n=6, m=5
int m,n=5;
m = ++n; // n=6, m=6
Por ejemplo la siguiente función retorna el primer primo siguiente (mayor o
igual) a n.
1
2
3
4
int next-prime(int n) {
while (!is-prime(n++)) { }
return n;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 75
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Operadores de auto incremento (cont.)
También hay autodecremento -- prefijo y postfijo.
1
2
3
1
2
int n=10;
while (n >= 0) cout << n-- << ", ";
cout << "Boom!!" << endl;
[mstorti@galileo garage]$$ ./boom.bin
10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, Boom!!
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 76
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Tipos de datos
Dijimos que C/C++ es un lenguaje de tipeo estático, es decir en el momento
de crear las variables hay que decir de que tipo son. Hay tipos de datos
built-in como enteros, floats, strings, que ya están definidos en el compilador,
y también el programador puede crear sus propios tipos, muchas veces por
composición. Por ejemplo si estamos creando la base de datos de una
empresa podemos querer tener un tipo de dato employee que contenga un
string (el nombre), un entero (el número de empleado) y un float (el sueldo).
Los tipos built-in son
• char un entero de al menos 8 bits, usualmente se usa para almacenar
•
•
•
caracteres.
int un entero de al menos 16 bits (2 bytes)
float un número de punto flotante con al menos 4 bytes (simple precisión)
double un número de punto flotante con al menos 8 bytes (doble
precisión).
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 77
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Tipos de datos (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Defining the four basic data
// types in C and C++
int main() {
// Definition without initialization:
char protein;
int carbohydrates;
float fiber;
double fat;
// Simultaneous definition & initialization:
char pizza = ’A’, pop = ’Z’;
int dongdings = 100, twinkles = 150,
heehos = 200;
float chocolate = 3.14159;
// Exponential notation:
double fudge-ripple = 6e-4;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 78
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Tipos de datos (cont.)
Como los tipos básicos tienen una cantidad de bits fija pueden representar un
tamaño máximo. Por ejemplo los enteros de 16 bits sólo pueden estar entre
-32768 y +32768. Además el tamaño del tipo (la cantidad de bits) puede
depender de la máquina y del compilador, entonce los valores máximos y
mı́nimos (los lı́mites) están definidos en headers float.h y limits.h,
1
2
3
4
5
6
1
2
3
#include <climits>
cout << "Minimum and maximum integers are "
<< endl << INT-MIN << " and " << INT-MAX
<< endl;
}
[mstorti@galileo garage]$$ ./intmax.bin
Minimum and maximum integers are
-2147483648 and 2147483647
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 79
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Especificadores
• Para representar enteros se utiliza un bit de los 32 disponibles para
•
•
•
representar el signo.
Si sólo se van a utilizar enteros positivos entonces podemos usar ese bit
para extender un factor 2 el rango.
int en el rango [-2147483648,2147483647]
unsigned int en el rango [0,4294967295]
unsigned es un specifier, otros son: signed, unsigned, short, long.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 80
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Especificadores (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//: C03:Specify.cpp
// Demonstrates the use of specifiers
#include <iostream>
using namespace std;
int main() {
char c;
unsigned char cu;
int i;
unsigned int iu;
short int is;
short iis; // Same as short int
unsigned short int isu;
unsigned short iisu;
long int il;
long iil; // Same as long int
unsigned long int ilu;
unsigned long iilu;
float f;
double d;
long double ld;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 81
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
22
23
24
25
26
27
28
29
30
31
32
33
34
35
cout
<< "\n char= " << sizeof(c)
<< "\n unsigned char = " << sizeof(cu)
<< "\n int = " << sizeof(i)
<< "\n unsigned int = " << sizeof(iu)
<< "\n short = " << sizeof(is)
<< "\n unsigned short = " << sizeof(isu)
<< "\n long = " << sizeof(il)
<< "\n unsigned long = " << sizeof(ilu)
<< "\n float = " << sizeof(f)
<< "\n double = " << sizeof(d)
<< "\n long double = " << sizeof(ld)
<< endl;
} ///:˜
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 82
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Especificadores (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[mstorti@galileo garage]$$ ./sizes.bin
char= 1
unsigned char = 1
int = 4
unsigned int = 4
short = 2
unsigned short = 2
long = 8
unsigned long = 8
float = 4
double = 8
long double = 16
[mstorti@galileo garage]$$
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 83
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Punteros
Al declarar variables lo que estamos haciendo es dar un nombre a un pedazo
de la memoria. Cuando decimos int n lo que estamos diciendo al compilador
es: resérveme 4 bytes de la memoria y a partir de ahora lo voy a llamar n. El
operador & nos muestra en que posición de la memoria fue alocada la variable
1
2
1
2
int n;
cout << "variable n is in position " << &n << endl;
[mstorti@galileo garage]$$ ./ptr.bin
variable n is in position 0x7fff1c46d92c
Los punteros son impresos normalmente en formato de hexadecimales, si
quisiéramos verlo en formato decimal podemos castear (convertir) el puntero
a un entero
1
2
1
2
int n;
cout << "variable n is in position " << (long)&n << endl;
[mstorti@galileo garage]$$ ./ptr.bin
variable n is in position 140737075615260
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 84
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Punteros (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
using namespace std;
int dog, cat, bird, fish;
void f(int pet) {
cout << "pet id number: " << pet << endl;
}
int main() {
int i, j, k;
cout << "f(): " << (long)&f << endl;
cout << "dog: " << (long)&dog << endl;
cout << "cat: " << (long)&cat << endl;
cout << "bird: " << (long)&bird << endl;
cout << "fish: " << (long)&fish << endl;
cout << "i: " << (long)&i << endl;
cout << "j: " << (long)&j << endl;
cout << "k: " << (long)&k << endl;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 85
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Punteros (cont.)
El resultado es
1
2
3
4
5
6
7
8
9
10
[mstorti@galileo garage]$$ ./pointers.bin
f(): 4196630
dog: 6295956
cat: 6295960
bird: 6295964
fish: 6295968
i: 140736631158572
j: 140736631158568
k: 140736631158564
[mstorti@galileo garage]$$
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 86
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Punteros (cont.)
• La dirección en memoria de un variable puede cambiar de una corrida a
•
•
•
1
2
otra.
Funciones, variables y globales parecen estar en sectores de la memoria
diferentes.
Enteros parecen ocupar 4 bytes.
Las posiciones en la memoria se pueden guardar en una variable de tipo
especial llamada puntero
int number;
int *number-p = &number;
• El sufijo _p o simplemente p indica que es un puntero (es sólo una
convención).
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 87
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Punteros (cont.)
• Algunos programadores ponen el * junto al tipo.
1
int* number-p;
Es totalmente equivalente, pero confuso,
1
int* number-p,n-p,m-p;
Declara a number_p, pero n_p y m_p son declarados enteros. Lo correcto es
1
int *number-p,*n-p,*m-p;
• Podemos asignar a una variable de tipo puntero la dirección de una
variable, lo cual nos permite modificarla a través de ese proxy
1
2
3
int number=100;
int *number-p = &number;
*number-p = 25; // Ahora number contiene 25!!
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 88
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Punteros (cont.)
• OJO: el hecho de declarar una variable de tipo puntero no significa que
esté apuntando a un objeto válido, es deber del programador asignarle al
puntero una posición válida, si no puede dar error en tiempo de ejecución
al querer usar el puntero.
1
2
3
4
5
int *p;
cout << "contenido de *p " << *p << endl; // ERROR
int x;
p = &x;
cout << "contenido de *p " << *p << endl; // OK
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 89
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Punteros (cont.)
Los punteros tienen un montón de usos, el primero que veremos es el de
causar que una función modifique un objeto. El mecanismo de paso de
variables en C/C++ es por copia.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;
void f(int a) {
cout << "&a = " << &a << endl;
cout << "a = " << a << endl;
a = 5;
cout << "a = " << a << endl;
}
int main() {
int x = 47;
cout << "&x = " << &x << endl;
cout << "x = " << x << endl;
f(x);
cout << "x = " << x << endl;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 90
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Punteros (cont.)
Imprime:
1
2
3
4
5
6
7
8
[mstorti@galileo sources]$$ ./try40.bin
&x = 0x7ffe99dd33ec
x = 47
&a = 0x7ffe99dd33bc
a = 47
a=5
x = 47
[mstorti@galileo sources]$$ x = 47
Como la variable a en f() es una copia, resulta que la modificación que se
hace en f() no persiste, de manera que queda el mismo valor.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 91
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Punteros (cont.)
En esta versión en cambio, pasamos la dirección donde está x:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;
void f(int* p) {
cout << "p = " << p << endl;
cout << "*p = " << *p << endl;
*p = 5;
cout << "p = " << p << endl;
}
int main() {
int x = 47;
cout << "x = " << x << endl;
cout << "&x = " << &x << endl;
f(&x);
cout << "x = " << x << endl;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 92
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Punteros (cont.)
Imprime:
1
2
3
4
5
6
7
8
[mstorti@galileo sources]$ ./try41.bin
x = 47
&x = 0x7ffcf3047dcc
p = 0x7ffcf3047dcc
*p = 47
p = 0x7ffcf3047dcc
x=5
[mstorti@galileo sources]$
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 93
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Referencias
Los punteros son muy útiles pero engorrosos porque hay que estar
dereferenciando al puntero cada vez. C++ introdujo las referencias que son
completamente equivalentes a los punteros pero evitan la dereferenciación.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
using namespace std;
void f(int& r) {
cout << "r = " << r << endl;
cout << "&r = " << &r << endl;
r = 5;
cout << "r = " << r << endl;
}
int main() {
int x = 47;
cout << "x = " << x << endl;
cout << "&x = " << &x << endl;
f(x); // Looks like pass-by-value,
// is actually pass by reference
cout << "x = " << x << endl;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 94
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Referencias (cont.)
Imprime:
1
2
3
4
5
6
7
8
[mstorti@galileo sources]$ ./try42.bin
x = 47
&x = 0x7ffd244d1aac
r = 47
&r = 0x7ffd244d1aac
r=5
x=5
[mstorti@galileo sources]$
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 95
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Punteros a void
• El compilador sólo acepta que asignemos a una variable de tipo int* la
dirección de una variable de tipo int, en otro caso da un error
int *p;
2 int n;
3 p = &n; // OK
4 double a;
5 p = &a; // Error
• El tipo void* permite almacenar un puntero a cualquier tipo de variable
1 void* vp;
2 char c;
3 int i;
4 float f;
5 double d;
6 vp = &c;
7 vp = &i;
8 vp = &f;
9 vp = &d;
1
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 96
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Punteros a void (cont.)
• Una vez que una dirección es asignada a un void* el compilador no puede
saber de que tipo es el objeto al cual apunta, y por lo tanto no se puede
dereferenciar
1
2
3
int i = 99;
void* vp = &i;
*vp = 3; // Error de compilacion
• Para poder recuperar el objeto tenemos que castear el puntero, de esa
forma le estamos diciendo al compilador que es del tipo indicado
1
2
3
int i = 99;
void* vp = &i;
*((int*)vp) = 3; // OK!
• Si casteamos al tipo incorrecto el compilador no protesta, pero se puede
producir un error en tiempo de ejecución
1
2
3
4
int i = 99;
void* vp = &i;
// Compila OK, posible error en tiempo de ejecución
*((string*)vp) = "Hello world";
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 97
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Scope de las variables
Una variable existe desde su definición hasta la siguiente llave que cierra (}).
Eso se llama el scope de la variable.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// How variables are scoped
int main() {
int scp1;
// scp1 visible here
{
// scp1 still visible here
//. . . . .
int scp2;
// scp2 visible here
//. . . . .
{
// scp1 & scp2 still visible here
//. .
int scp3;
// scp1, scp2 & scp3 visible here
// . . .
} // scp3 destroyed here
// scp3 not available here
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 98
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
19
20
21
22
23
24
25
// scp1 & scp2 still visible here
// . . .
} // scp2 destroyed here
// scp3 & scp2 not available here
// scp1 still visible here
//. .
} // scp1 destroyed here
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 99
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Definiendo variables on-the-fly
En C todas las variables deben ser definidas al comienzo del scope. En C++
se pueden definir en cualquier lugar.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// On-the-fly variable definitions
#include <iostream>
using namespace std;
int main() {
//. .
{ // Begin a new scope
int q = 0; // C requires definitions here
//. .
// Define at point of use:
for(int i = 0; i < 100; i++) {
q++; // q comes from a larger scope
// Definition at the end of the scope:
int p = 12;
}
int p = 1; // A different p
} // End scope containing q & outer p
cout << "Type characters:" << endl;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 100
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
}
while(char c = cin.get() != ’q’) {
cout << c << " wasn’t it" << endl;
if(char x = c == ’a’ | | c == ’b’)
cout << "You typed a or b" << endl;
else
cout << "You typed " << x << endl;
}
cout << "Type A, B, or C" << endl;
switch(int i = cin.get()) {
case ’A’: cout << "Snap" << endl; break;
case ’B’: cout << "Crackle" << endl; break;
case ’C’: cout << "Pop" << endl; break;
default: cout << "Not A, B or C!" << endl;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 101
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Definiendo variables on-the-fly (cont.)
Las variables que están fuera de todas las funciones son globales, su scope
es todo el programa, incluı́do dentro de las funciones.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// == file1.cpp ==
// Demonstration of global variables
#include <iostream>
using namespace std;
int globe;
void func();
int main() {
globe = 12;
cout << globe << endl;
func(); // Modifies globe
cout << globe << endl;
}
// == file2.cpp ==
// Accessing external global variables
extern int globe;
// (The linker resolves the reference)
void func() {
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 102
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
19
20
}
globe = 47;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 103
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Variables locales
Las variables que existen dentro de un scope son locales, también se les
llama automáticas ya que son creadas en el momento de llegar a ese bloque.
La memoria que le es asignada no tiene porque ser siempre la misma, por lo
tanto la variable no retiene el valor que le fue asignado antes.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void f(int x) {
int a;
cout << "a en f(): " << a << endl;
cout << "&a en f(): " << &a << endl;
a=x;
cout << "a en f() despues de asignar: " << a << endl;
}
void g(int x) {
int a;
cout << "a en g(): " << a << endl;
cout << "&a en g(): " << &a << endl;
a=x;
cout << "a en g() despues de asignar: " << a << endl;
}
void h(int x) {
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 104
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
int a;
f(435);
cout << "a en h(): " << a << endl;
cout << "&a en h(): " << &a << endl;
a=x;
cout << "a en h() despues de asignar: " << a << endl;
}
int main() {
f(23);
g(45);
f(23);
g(45);
h(234);
return 0;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 105
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Variables locales (cont.)
El resultado es:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[mstorti@galileo garage]$$ ./try2.bin
a en f(): 0
&a en f(): 0x7fff6df56d1c
a en f() despues de asignar: 23
a en g(): 23
&a en g(): 0x7fff6df56d1c
a en g() despues de asignar: 45
a en f(): 45
&a en f(): 0x7fff6df56d1c
a en f() despues de asignar: 23
a en g(): 23
&a en g(): 0x7fff6df56d1c
a en g() despues de asignar: 45
a en f(): 59
&a en f(): 0x7fff6df56cdc
a en f() despues de asignar: 435
a en h(): 45
&a en h(): 0x7fff6df56d1c
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 106
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
19
20
a en h() despues de asignar: 234
[mstorti@galileo garage]$$
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 107
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Punteros a variables locales
Si una variable sale de scope, es un error tratar de utilizar punteros que
apuntaban a esa variable.
1
2
3
4
5
6
7
8
int *p;
for (int j=0; j<N; j++) {
int z;
p = &z;
...
}
// ERROR (z no existe mas)
cout << "contenido de *p " << *p << endl;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 108
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Variables estáticas
Si queremos que el área asignada a una variable local sea siempre el mismo,
entonces le agregamos el keyword static. Un ejemplo clásico es una función
que cuenta cuantas veces fue llamada:
1
2
3
4
5
6
7
8
9
10
11
void f() {
static int count=0;
cout << "f() fue llamada " << count << " veces" << endl;
cout++;
}
int main() {
for (int j=0; j<10; j++)
f();
return 0;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 109
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Variables estáticas (cont.)
El resultado es:
1
2
3
4
5
6
7
8
9
10
11
12
[mstorti@galileo garage]$ ./try14.bin
f() fue llamada 0 veces
f() fue llamada 1 veces
f() fue llamada 2 veces
f() fue llamada 3 veces
f() fue llamada 4 veces
f() fue llamada 5 veces
f() fue llamada 6 veces
f() fue llamada 7 veces
f() fue llamada 8 veces
f() fue llamada 9 veces
[mstorti@galileo garage]$
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 110
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Constantes
Si se utilizará muchas veces un valor que es constante se pueden hacer a
través de un macro
1
#define PI 3.141459
o bien a través de una variable de tipo const
1
const double pi = 3.141459;
Es más prolijo esto último (le permite al compilador hacer chequeo de tipo).
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 111
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Operadores. Asignación
El caracter = se utiliza como el operador de asignación:
1
A=4;
Lo que está a la izquierda de = es el lvalue y lo que está a la derecha el rvalue.
El rvalue puede ser cualquier expresión. El compilador la evalua y asigna el
resultado a lo que está en el lvalue. Ahora bien lo que está en el lvalue no
puede ser cualquier cosa, debe ser una variable o cualquier otra cosa a la
cual se le pueda asignar un valor. Por ejemplo no puede ser una constante, es
decir no podemos hacer
1
4=A;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 112
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Operadores matemáticos
Los operadores matemáticos binarios usuales son +-*/. Cada uno de ellos se
puede usar en forma de acumulación +=, -=, *=, /=. Por ejemplo
1
x += 5;
es equivalente a
1
x = x + 5;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 113
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Operadores relacionales
Son
1
>, <, >=, <=, ==, !=
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 114
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Operadores lógicos
Son && (and) y || (or). Recordar que en C/C++ muchos tipos se castean
automáticamente a bool, siendo 0 el valor falso y cualquier otro valor
verdadero. Cuando se imprimen los valores booleanos dan 0 o 1. ! es la
negación.
Son operadores cortocircuitados es decir si hacemos
1
expr1 && expr2
entonces primero se evalua expr1 y si da falso, entonces expr2 NO se evalúa,
ya que no es necesario porque la expresión lógica resultará en falso de todas
formas. Eso puede ser importante, por ejemplo
1
if (n>0 && m/n!=3) . . .
está garantizado que no dará error si n==0 ya que si es ası́ directamente la
división por n no se hará. Lo mismo ocurre en
1
expr1 | | expr2
si la primera da verdadero.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 115
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
El operador hook
Es una forma muy compacta de escribir un if-else. Por ejemplo esta expresión
calcula el mı́nimo de dos valores
1
x = (m<n ? m : n);
Se puede usar también en un lvalue. La siguiente expresión asigna al menor
de m,n el valor 23.
1
(m<n ? m : n) = 23;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 116
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Errores comunes con los operadores
• Las reglas de precedencia a veces son simples, pero si se escriben
•
expresiones complejas ya no. Ante la duda utilizar paréntesis.
No confundir = con ==.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 117
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Operadores de cast
• Si el compilador ve que estamos mezclando tipos en una asignación,
insertará una operación de cast (conversión de tipo) automáticamente
1
2
3
4
5
6
7
8
9
10
int x=5;
double z=x; // OK
z=23.3;
x=z; // se pierde la mantisa (truncamiento)
x = (int) z; // cast explicito
x = int(z); // otra forma del cast explicito
int ixp = &x; // error, no puede convertir ptr a int
long int ixp2 = (long int)&x; // OK!
long int ixp3 = static-cast<long int>(&x); // OK!
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 118
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Operador sizeof
• Retorna el tamaño de una variable o tipo en bytes
1 cout << "sizeof(char) " << sizeof(char) << endl; // ->1
2 cout << "sizeof(int) " << sizeof(int) << endl; // ->4
3 cout << "sizeof(float) " << sizeof(float) << endl; // ->4
4 cout << "sizeof(double) " << sizeof(double) << endl; // ->8
5
6 double a;
7 cout << "sizeof(a) " << sizeof(a) << endl; // ->8
8 cout << "sizeof(&a) " << sizeof(&a) << endl; // ->8 (in x86 64)
9 int x;
10 cout << "sizeof(&x) " << sizeof(&x) << endl; // ->8 (in x86 64)
-
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 119
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
typedef: Aliases de tipos
• Permite hacer un alias de un tipo a un nuevo tipo
1 typedef unsigned long int ulong;
2 . . .
3 ulong x;
• Simple para tipos básicos, más complicado para punteros
1 typedef int *int p;
• La regla es que se escribe una lı́nea como la declaración de una variable
•
1
2
con typedef al principio y reemplazando la variable por el tipo.
Esto permite hacer expresiones más cortas pero además tiene un uso muy
importante. Permitir cambiar de tipo todas las variables de un programa
typedef float scalar;
scalar i,j,k;
Para cambiar todo el programa a doble precisión:
1
typedef double scalar;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 120
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Estructuras
• Se pueden definir nuevos tipos agrupando varios miembros en una
estructura. Los miembros de la estructura se toman con el operador .:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct A {
char c;
int m;
float f;
double b;
};
void printa(A a) {
cout << "structure is (" << a.c << "," << a.m << ","
<< a.f << "," << a.b << ")" << endl;
}
...
A a1, a2;
a1.c = ’h’;
a2.m = 23;
printa(a1);
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 121
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Estructuras (cont.)
Se pueden tomar punteros a estructuras y enlazarlas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
struct cell {
char c;
double x;
cell *next;
};
int main() {
cell c1,c2,c3;
c1.c = ’a’; c1.x = 1; c1.next = &c2;
c2.c = ’b’; c2.x = 2; c2.next = &c3;
c3.c = ’c’; c3.x = 3; c3.next = &c1;
cell *cp = &c1;
for (int k=0; k<20; k++) {
cout << "cp " << cp << ", c "
<< (*cp).c << ", x " << (*cp).x << endl;
cp = (*cp).next;
}
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 122
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Estructuras (cont.)
1
2
3
4
cell
c1.c
c2.c
c3.c
c1,c2,c3;
= ’a’; c1.x = 1; c1.next = &c2;
= ’b’; c2.x = 2; c2.next = &c3;
= ’c’; c3.x = 3; c3.next = &c1;
c1
c='a' x=1
c2
c3
c='c' x=3
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
next
next
c='b' x=2
next
slide 123
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Estructuras (cont.)
El resultado es
1
2
3
4
5
6
7
8
9
[mstorti@galileo garage]$$ ./try8.bin
cp 0x7fff571b2d20, c a, x 1
cp 0x7fff571b2d00, c b, x 2
cp 0x7fff571b2ce0, c c, x 3
cp 0x7fff571b2d20, c a, x 1
...
cp 0x7fff571b2d20, c a, x 1
cp 0x7fff571b2d00, c b, x 2
[mstorti@galileo garage]$$
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 124
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Arrow operator
Como en el ejemplo anterior es muy común la compinación (*cp).x es decir
tener un puntero a una estructura cp y querer tomar un miembro x de la
estructura apuntada. Como es tan común hay un atajo sintáctico para eso
1
(*cp).x es equivalente a cp->x
Entonces el lazo del programa anterior pasa a ser
1
2
3
4
5
for (int k=0; k<20; k++) {
cout << "cp " << cp << ", c " << cp->c
<< ", x " << cp->x << endl;
cp = cp->next;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 125
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Enum’s
• Supongamos que queremos definir una estructura shape que contiene una
forma geométrica, digamos las coordenadas x,y de su centro y un entero
que indica su forma. Para ello incluimos un entero gtype (por geometric
type) que define que tipo de forma es. Podemos por ejemplo asignar
arbitrariamente gtype=0 para cı́rculos, 1=cuadrados, 2=rectángulos.
1
2
3
4
struct shape {
double x,y;
int gtype;
};
Entonces una función que imprime la forma serı́a algo ası́ como
1
2
3
4
5
6
void draw(shape s) {
if (s.gtype==0) //. . . imprime un circulo
else if (s.gtype==1) //. . . imprime un cuadrado
else if (s.gtype==2) //. . . imprime un rect
...
}
El problema con esto es que tenemos que guardar mentalmente una tabla
para saber que entero correspondı́a a cada forma.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 126
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Enum’s (cont.)
Una posibilidad es usar macros
1
2
3
4
5
6
7
8
9
10
#define CIRCLE 0
#define SQUARE 1
#define RECTANGLE 2
void draw(shape s) {
if (s.gtype==CIRCLE) //. . . imprime un circulo
else if (s.gtype==SQUARE) //. . . imprime un cuadrado
else if (s.gtype==RECTANGLE) //. . . imprime un rect
...
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 127
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Enum’s (cont.)
Pero, como ya dijimos, es preferible no usar macros, para esto está el enum:
1
2
3
4
5
6
7
8
9
10
11
12
13
enum GeoType { circle, square, rectangle};
struct shape {
double x,y;
GeoType gtype;
};
void draw(shape s) {
if (s.gtype==circle) //. . . imprime un circulo
else if (s.gtype==square) //. . . imprime un cuadrado
else if (s.gtype==rectangle) //. . . imprime un rect
...
}
• Internamente los enums son enteros, pero esto es transparente para
•
nosotros.
El compilador traduce cada identificador de la lista a un entero
consecutivo.
Se puede forzar a que tomen un valor especı́fico
•
1 enum GeoType { circle=5, square=10, rectangle=15};
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 128
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Arreglos de estructuras
• Vimos que podemos definir arreglos como int v[100].
• También lo podemos hacer con estructuras cell cellv[100]
• Los elementos son guardados en forma consecutiva
1 struct cell {
2
double x;
3
cell *next;
4 };
5
6 for (int j=0; j<4; j++)
7
cout << "&cellv[" << j << "] "
8
<< (long int)&cellv[j] << endl;
9 . . .
10 &cellv[0] 140736201505632
11 &cellv[1] 140736201505648
12 &cellv[2] 140736201505664
ya que el tamaño de la celda es de 16 bytes (8 para el doble y 8 para el
puntero):
1
2
3
cout << "sizeof(cell): " << sizeof(cell) << endl;
...
sizeof(cell): 16
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 129
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Punteros y arreglos
Si imprimimos un arreglo, el compilador lo imprime como hexadecimal, o sea
como si fuera un puntero
1
2
3
4
int v[100];
cout << v << endl;
...
-> 0x7fff7e388420
Esto es porque el compilador sólo almacena para el vector la dirección donde
comienza el área asignada al vector. Esto lo podemos verificar imprimiento la
dirección del primer elemento
1
2
cout << &cellv[0] << endl;
-> 0x7fff7e388420
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 130
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Punteros y arreglos (cont.)
Si tomamos un puntero al primer elemento podemos manipular al vector a
través de ese puntero
1
2
3
int v[100];
int *p= &v[0];
for (int j=0; j<100, j++) *(p+j) = 100*j;
De hecho en la mayorı́a de los casos punteros y arreglos son intercambiables,
por ejemplo a los punteros se les puede aplicar el operador [] de manera que
se lo puede utilizar como un vector.
1
2
3
int v[100];
int *p= &v[0];
for (int j=0; j<1000, j++) p[j] = 100*j;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 131
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Arreglos de punteros
• También se pueden tener arreglos de punteros
1 int *v[100]; // arreglo de 100 punteros a enteros
• Los arreglos de caracteres, son de tipo char* entonces si queremos tener
un arreglo de “strings de C”, tenemos un arreglo de arreglos de char, o lo
que es equivalente a arreglos de punteros a char
1
2
char *as[ ];
char **as; // equivalente
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 132
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Arreglos de punteros (cont.)
• Un caso frecuente de esto es la segunda forma de llamada a main(). Si
llamamos a nuestro programa con argumentos
1
2
3
4
5
int main(int argc,char **argv) {
for (int j=0; j<argc; j++)
cout << j << ": " << argv[j] << endl;
return 0;
}
El resultado es
1
2
3
4
5
6
7
8
9
10
$$
0:
1:
2:
3:
4:
5:
6:
7:
8:
./try10.bin -u mstorti -d 453 -l 34 -f 34.56
./try10.bin
-u
mstorti
-d
453
-l
34
-f
34.56
El shell (en este caso bash) divide los argumentos pasados en la lı́nea de
comando por whitespace y construye un arreglo de strings
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 133
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Arreglos de punteros (cont.)
• El acceso a elementos de un arreglo de C es extremadamente rápido.
• Sin embargo si se accede a posiciones más allá de la última posición del
vector se puede producir un error
int v[100];
2 . . .
3 v[100] = x; // Muy probablemente SIGSEGV o SEGFAULT
• Se debe conocer el tamaño del vector en tiempo de compilación (hay una
1
•
forma de hacerlo dinámico, con new[]/delete[] o malloc()/free().
La clase vector<> es mucho más versátil y más segura.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 134
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Arreglos de punteros (cont.)
Podemos verificar que los elementos de un vector están en posiciones
contiguas.
1
2
3
4
5
int a[10];
cout << "sizeof(int) = "<< sizeof(int) << endl;
for(int i = 0; i < 10; i++)
cout << "&a[" << i << "] = "
<< (long)&a[i] << endl;
produce
1
2
3
4
5
6
$$ ./try17.bin
sizeof(int) = 4
&a[0] = 140736359816368
&a[1] = 140736359816372
&a[2] = 140736359816376
&a[3] = 140736359816380
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 135
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Aritmética de punteros
Se pueden hacer cuentas con punteros de tipo ptr = ptr + int y todas las
derivadas, por ejemplo
1
2
3
4
5
ptr = ptr + int
int = ptr - ptr
ptr += int
ptr++
ptr--
En todas estas operaciones el entero indica posiciones en el vector, no bytes.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 136
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Aritmética de punteros (cont.)
1
2
3
4
5
6
7
8
9
10
int i[10];
double d[10];
int* ip = i;
double* dp = d;
cout << "ip = " <<
ip++;
cout << "ip = " <<
cout << "dp = " <<
dp++;
cout << "dp = " <<
(long)ip << endl;
(long)ip << endl;
(long)dp << endl;
(long)dp << endl;
produce
1
2
3
4
5
[mstorti@galileo garage]$$ ./try18.bin
ip = 140733418503296
ip = 140733418503300
dp = 140733418503216
dp = 140733418503224
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 137
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Tamaños de estructuras
Cuando se usan estructuras con tipos mezclados puede ser que el tamaño del
tipo combinado no sea igual a la suma de los tamaños de los tipos (pero
seguro es mayor o igual) porque el compilador tiene que alinear los tipos.
1
2
3
4
struct A {
char c;
double d;
};
da sizeof(A) -> 16, y
1
2
struct B { char c; double d; char c2; };
struct C { char c; char c2; double d; };
da
1
2
sizeof(B) -> 24
sizeof(C) -> 16
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 138
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Programación Orientada
a Objetos
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 139
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Abstracción de datos
Un contenedor de elementos de longitud arbitraria
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef CSTASH-H
#define CSTASH-H
struct CStash {
int size; // Size of each space
int quantity; // Number of storage spaces
int next; // Next empty space
// Dynamically allocated array of bytes:
unsigned char* storage;
};
void initialize(CStash* s, int size);
void cleanup(CStash* s);
int add(CStash* s, const void* element);
void* fetch(CStash* s, int index);
int count(CStash* s);
void inflate(CStash* s, int increase);
#endif
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 140
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Abstracción de datos (cont.)
1
2
3
4
5
6
7
struct CStash {
int size; // Size of each space
int quantity; // Number of storage spaces
int next; // Next empty space
// Dynamically allocated array of bytes:
unsigned char* storage;
};
size
used
free
store
quantity
next
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 141
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Abstracción de datos (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Implementation of example C-like library
// Declare structure and functions:
#include "./cstash.h"
#include <iostream>
#include <cassert>
using namespace std;
// Quantity of elements to add
// when increasing storage:
const int increment = 100;
void initialize(CStash* s, int sz) {
s->size = sz;
s->quantity = 0;
s->storage = 0;
s->next = 0;
}
int add(CStash* s, const void* element) {
if(s->next >= s->quantity) //Enough space left?
inflate(s, increment);
// Copy element into storage,
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 142
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// starting at next empty space:
int startBytes = s->next * s->size;
unsigned char* e = (unsigned char*)element;
for(int i = 0; i < s->size; i++)
s->storage[startBytes + i] = e[i];
s->next++;
return(s->next - 1); // Index number
}
void* fetch(CStash* s, int index) {
// Check index boundaries:
assert(0 <= index);
if(index >= s->next)
return 0; // To indicate the end
// Produce pointer to desired element:
return &(s->storage[index * s->size]);
}
int count(CStash* s) {
return s->next; // Elements in CStash
}
void inflate(CStash* s, int increase) {
assert(increase > 0);
int newQuantity = s->quantity + increase;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 143
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
int newBytes = newQuantity * s->size;
int oldBytes = s->quantity * s->size;
unsigned char* b = new unsigned char[newBytes];
for(int i = 0; i < oldBytes; i++)
b[i] = s->storage[i]; // Copy old to new
delete [ ](s->storage); // Old storage
s->storage = b; // Point to new memory
s->quantity = newQuantity;
}
void cleanup(CStash* s) {
if(s->storage != 0) {
cout << "freeing storage" << endl;
delete [ ]s->storage;
}
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 144
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Abstracción de datos (cont.)
• CStash es un tipo que permite almacenar una cantidad ilimitada de
•
•
•
•
•
•
elementos de tamaño size.
Tiene un área de almacenamiento interno unsigned char *storage.
Se pueden agregar elementos con add(), si el tamaño del almacenamiento
interno no es suficiente entences se incrementa en una dada cantidad
(por default 100).
initialize() realiza la inicializacion de la estructura, poniendo a cero los
diferentes contadores y el tamaño de los elementos al valor entrado por el
usuario (int sz).
add() agrega un elemento copiándolo byte por byte a storage. Si el tamaño
no es suficiente llama a inflate() para alocar una nueva área recopiando
todo el área previa y agregando el nuevo elemento.
quantity es el número de lugares disponibles
next es la cantidad de lugares realmente ocupados.
fetch() retorna el puntero al lugar donde comienza el elemento en la
posición index. Primero chequea que efectivamente el ı́ndice esté en el
rango de valores apropiados (0<=index<next). En caso contrario retorna un
puntero nulo. Está garantizado que el puntero nulo no apunta a ningún
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 145
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
•
•
lado de la memoria.
count() retorna la cantidad de elementos que hay en el contenedor.
Simplemente retorna next.
Alocación dinámica de memoria: Como no sabemos en principio que
tamaño va a tomar el área de memoria vamos alocando dinámicamente
con el operador new
new unsigned char[newBytes];
• En general se puede hacer
1 t = new Type; // aloca un solo objeto
2 tp = new Type[count]; // aloca un arreglo de count objetos
• El área utilizada debe ser liberada. Si no (y si la alocación se hace
1
repetidamente) se produce un memory leak.
delete t;
2 delete[ ] tp;
• Las áreas de memoria reservadas con new se alocan en el heap. Si el heap
1
•
se acaba la alocación da un error (OJO que no necesariamente retorna un
puntero nulo).
Los pedazos de memoria alocados con new pueden crear fragmentación
de la memoria. (No hay un defragmentador).
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 146
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Abstracción de datos (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include "./cstash.h"
#include <fstream>
#include <iostream>
#include <string>
#include <cassert>
using namespace std;
int main() {
// Define variables at the beginning
// of the block, as in C:
CStash intStash, stringStash;
int i;
char* cp;
ifstream in;
string line;
const int bufsize = 80;
// Now remember to initialize the variables:
initialize(&intStash, sizeof(int));
for(i = 0; i < 100; i++)
add(&intStash, &i);
for(i = 0; i < count(&intStash); i++)
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 147
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
}
cout << "fetch(&intStash, " << i << ") = "
<< *(int*)fetch(&intStash, i)
<< endl;
// Holds 80-character strings:
initialize(&stringStash, sizeof(char)*bufsize);
in.open("./trycstash.cpp");
assert(in);
while(getline(in, line))
add(&stringStash, line.c-str());
i = 0;
while((cp = (char*)fetch(&stringStash,i++))!=0)
cout << "fetch(&stringStash, " << i << ") = "
<< cp << endl;
cleanup(&intStash);
cleanup(&stringStash);
return 0;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 148
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Abstracción de datos (cont.)
Resultado:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[mstorti@galileo garage]$ ./trycstash.bin
fetch(&intStash, 0) = 0
fetch(&intStash, 1) = 1
fetch(&intStash, 2) = 2
fetch(&intStash, 3) = 3
...
fetch(&intStash, 97) = 97
fetch(&intStash, 98) = 98
fetch(&intStash, 99) = 99
0: #include "./cstash.h"
1: #include <fstream>
2: #include <iostream>
3: #include <string>
...
37: cleanup(&stringStash);
38: return 0;
39: }
freeing storage
freeing storage
[mstorti@galileo garage]$
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 149
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
POO básica
La librerı́a que creamos tiene dos problemas básicos:
• Serı́a bueno que la construcción y destrucción de los objetos fuera
•
automática.
Polución del espacio de nombres: Si necesitamos otro contenedor no
vamos a poder usar los nombres initialize() y cleanup(). Una posible
solución serı́a usar nombres con prefijos CStash_initialize(),
CStash_cleanup() ...
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 150
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
POO básica (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct Stash {
int size; // Size of each space
int quantity; // Number of storage spaces
int next; // Next empty space
// Dynamically allocated array of bytes:
unsigned char* storage;
// Functions!
void initialize(int size);
void cleanup();
int add(const void* element);
void* fetch(int index);
int count();
void inflate(int increase);
};
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 151
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
POO básica (cont.)
• Ahora las funciones aparecen dentro de la estructura, de manera que esta
•
1
2
actúa como un namespace, de manera que la funciones se llaman ahora
Stash::initialize(), Stash::cleanup()
No hace falta pasar a las funciones el puntero al objeto. Esto se hace
automáticamente llamando a la función como miembro de un objeto
Stash s1,s2,s3;
s1.initialize(10);
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 152
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
POO básica (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// C library converted to C++
// Declare structure and functions:
#include "CppLib.h"
#include <iostream>
#include <cassert>
using namespace std;
// Quantity of elements to add
// when increasing storage:
const int increment = 100;
void Stash::initialize(int sz) {
size = sz;
quantity = 0;
storage = 0;
next = 0;
}
int Stash::add(const void* element) {
if(next >= quantity) // Enough space left?
inflate(increment);
// Copy element into storage,
// starting at next empty space:
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 153
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
int startBytes = next * size;
unsigned char* e = (unsigned char*)element;
for(int i = 0; i < size; i++)
storage[startBytes + i] = e[i];
next++;
return(next - 1); // Index number
}
void* Stash::fetch(int index) {
// Check index boundaries:
assert(0 <= index);
if(index >= next)
return 0; // To indicate the end
// Produce pointer to desired element:
return &(storage[index * size]);
}
int Stash::count() {
return next; // Number of elements in CStash
}
void Stash::inflate(int increase) {
assert(increase > 0);
int newQuantity = quantity + increase;
int newBytes = newQuantity * size;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 154
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
int oldBytes = quantity * size;
unsigned char* b = new unsigned char[newBytes];
for(int i = 0; i < oldBytes; i++)
b[i] = storage[i]; // Copy old to new
delete [ ]storage; // Old storage
storage = b; // Point to new memory
quantity = newQuantity;
}
void Stash::cleanup() {
if(storage != 0) {
cout << "freeing storage" << endl;
delete [ ]storage;
}
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 155
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
POO básica (cont.)
• Adentro de las funciones miembro no es necesario dereferenciar al objeto
•
1
2
3
4
5
6
7
8
para obtener los miembros size, quantity. Es decir en vez de aparecer
s->size ahora sólo aparece size, lo que ocurre es que al llamar
s1.initialize() la variable size corresponde al del objeto s1.
Si uno necesita conocer el puntero a la estructura en la que estoy en este
momento se usa el keyword this que es un puntero al objeto en el que
estamos parados
void Stash::initialize(int sz) {
cout << "this: " << this << endl;
...
}
Stash s1;
cout << "&s1: " << &s1 << endl;
s1.initialize();
Imprimen el mismo puntero.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 156
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
POO básica (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Test of C++ library
#include "CppLib.h"
#include ". ./require.h"
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main() {
Stash intStash;
intStash.initialize(sizeof(int));
for(int i = 0; i < 100; i++)
intStash.add(&i);
for(int j = 0; j < intStash.count(); j++)
cout << "intStash.fetch(" << j << ") = "
<< *(int*)intStash.fetch(j)
<< endl;
// Holds 80-character strings:
Stash stringStash;
const int bufsize = 80;
stringStash.initialize(sizeof(char) * bufsize);
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 157
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
22
23
24
25
26
27
28
29
30
31
32
33
34
}
ifstream in("CppLibTest.cpp");
assure(in, "CppLibTest.cpp");
string line;
while(getline(in, line))
stringStash.add(line.c-str());
int k = 0;
char* cp;
while((cp =(char*)stringStash.fetch(k++)) != 0)
cout << "stringStash.fetch(" << k << ") = "
<< cp << endl;
intStash.cleanup();
stringStash.cleanup();
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 158
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
POO básica (cont.)
• Las llamadas a funciones de la librerı́a se convierten ası́
1 CStash initialize(&s1,sz);
2 s1.initialize(size);
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 159
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Inclusion de headers
• Algunos headers pueden incluir a otros, por ejemplo el header de una
librerı́a lib1.h puede incluir iostream. Entonces si otra librerı́a lib2.h
también incluye iostream, al querer incluir a las dos librerı́as
#include <lib1.h>
2 #include <lib2.h> // Incluye iostream 2 veces -> error
• No hay problema con las funciones, pero si con las estructuras (y clases).
• Se utiliza un mecanismo con macros para evitar la doble inclusión.
1
Podemos usar los macros para incluir condicionalmente partes del
código.
1
2
3
4
5
6
7
#define FLAG
#ifdef FLAG
//. . .
#else
//. . .
#endif
Notar que es muy diferente este condicional del preprocesador que el
if-else de C++. En el del preprocesador sólo uno de los bloques se
compila. Quiere decir que se puede usar para usar diferentes pedazos de
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 160
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
código que de otra forma no compiları́a. Por ejemplo
#ifdef HAS-PETSC
2 //. . . Version que usa la libreria PETSC
3 #else
4 //. . . Version alternativa
5 #endif
• El macro se puede definir usando un #define FLAG como arriba, o también
1
•
al compilar usando $$ g++ -DFLAG ...
Lo contrario de definir un macro es hacerlo indefinido con #undef FLAG, a
partir de ahi #ifdef FLAG da falso.
#undef se puede usar para redefinir macros
•
1 #define MAX SIZE
2 . . . .
3 #define MAX SIZE
1 #define MAX SIZE
2
3 . . .
4 #undef MAX SIZE
5 #define MAX SIZE
-
100
1000 // -> Error
100
1000 // OK!
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 161
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Inclusion de headers (cont.)
• Para evitar la doble inclusión se utiliza un macro de protección
1 #ifndef STASH H
2 #define STASH H
3 // Type declaration here. . .
4 #endif // STASH H
• Ahora si se incluye dos veces el header no hay problema, ya que la
segunda vez en realidad no es incluido.
#include <stash.h>
2 #include <stash.h> // no es incluido esta vez!!
• El macro centinela STASH_H debe ser único para ese archivo. Si otro
1
archivo usa el mismo macro centinela entonces sus declaraciones no son
incluidas
1
2
#include <libreria1/stash.h>
#include <libreria2/stash.h> // Error: este no es incluido
Deberian usar LIBRERIA1_STASH_H y LIBRERIA2_STASH_H.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 162
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Inclusion de headers (cont.)
• Si en un header mylib.h se utilizan elementos de iostream es tentador
•
•
poner un using namespace std; en el header, para no tener que andar
poniendo el namespace std explı́citamente (e.g. std::cout).
Lamentablemente esto producirı́a que si un usuario incluye mylib.h todo
su código pierde la protección del namespace y volvemos a la situación
que querı́amos impedir con los namespace: la colisión de nombres.
Por lo tanto la regla es: NO usar using namespace.. en los headers, sólo en
los .cpp
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 163
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Estructuras enlazadas
• La siguiente estructura Stack representa una pila implementada con
celdas enlazadas. Las celdas son de otra estructura llamada Link que
contiene el dato data y un puntero a la siguiente celda next.
1
2
3
4
5
struct Link {
void* data;
Link* next;
void initialize(void* dat, Link* nxt);
};
Stack S
head
data
next
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
data
next
data
next
data
slide 164
next
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Estructuras enlazadas (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct Link {
void* data;
Link* next;
void initialize(void* dat, Link* nxt);
};
struct Stack {
Link *head;
void initialize();
void push(void* dat);
void* peek();
void* pop();
void cleanup();
};
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 165
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Estructuras enlazadas (cont.)
• La función push() mete un nuevo elemento en la pila, peek() retorna un
•
puntero al elemento en el tope de la pila. pop() elimina un elemento del
tope. initialize() y cleanup() son como antes: se encargan de la
inicialización y destrucción de la estructura.
El tipo de las celdas Link sólo se usará con la clase Stack. Si nuestra
librerı́a quiere además definir un tipo Queue que representa una cola, con
celdas enlazadas, entonces no podrá usar el mismo nombre Link para sus
celdas.
Para evitar esta colisión ponemos la clase Link adentro de la clase Stack
•
1 struct Stack {
2
struct Link {
3
void* data;
4
Link* next;
5
void initialize(void* dat, Link* nxt);
6
} *head;
7
void initialize();
8
void push(void* dat);
9
void* peek();
10
void* pop();
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 166
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
void cleanup();
12 };
• Notar que al definir el tipo Link en la misma declaración del tipo se define
11
un puntero Link *head a la primera celda. Por supuesto se puede hacer
por separado también
1
2
3
4
•
•
struct Link {
...
};
Link *head;
Por eso las definiciones de estructuras struct Type {...}; terminan en un
punto y coma, ya que allı́ se pueden definir objetos de tipo Type al mismo
tiempo que se define el nuevo tipo.
Notar que cada estructura Stack y Link tienen su función de inicialización
initialize().
Link no tiene cleanup(), el mismo usario es responsable de liberar el
espacio apuntado por data, si existe.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 167
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Estructuras enlazadas (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Linked list with nesting
#include "Stack.h"
#include ". ./require.h"
using namespace std;
void
Stack::Link::initialize(void* dat, Link* nxt) {
data = dat;
next = nxt;
}
void Stack::initialize() { head = 0; }
void Stack::push(void* dat) {
Link* newLink = new Link;
newLink->initialize(dat, head);
head = newLink;
}
void* Stack::peek() {
require(head != 0, "Stack empty");
return head->data;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 168
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
24
25
26
27
28
29
30
31
32
33
34
35
36
void* Stack::pop() {
if(head == 0) return 0;
void* result = head->data;
Link* oldHead = head;
head = head->next;
delete oldHead;
return result;
}
void Stack::cleanup() {
require(head == 0, "Stack not empty");
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 169
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Estructuras enlazadas (cont.)
Uso de Stack
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Test of nested linked list
#include "Stack.h"
#include ". ./require.h"
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
int main(int argc, char* argv[ ]) {
requireArgs(argc, 1); // File name is argument
ifstream in(argv[1]);
assure(in, argv[1]);
Stack textlines;
textlines.initialize();
string line;
// Read file and store lines in the Stack:
while(getline(in, line))
textlines.push(new string(line));
// Pop the lines from the Stack and print them:
string* s;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 170
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
21
22
23
24
25
26
}
while((s = (string*)textlines.pop()) != 0) {
cout << *s << endl;
delete s;
}
textlines.cleanup();
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 171
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Más sobre scoping
Si existen varias versiones de variables con un mismo nombre, la que se ve
es la del scope mas interno. Se puede acceder a las otras utilizando el
operador de scope apropiado. Para las globales hay que usar el scop :: (sin
nada a la izquierda).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Global scope resolution
int a;
void f() {}
struct S {
int a;
void f();
};
void S::f() {
::f(); // Would be recursive otherwise!
::a++; // Select the global a
a--; // The a at struct scope
}
int main() { S s; f(); }
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 172
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Tipos Abstractos de Datos (ADT)
Con este ejemplo hemos visto una idea fundamental de C++ que es incluir
funciones adentro de las estructuras. Este nuevo tipo de estructura es
llamado un Tipo Abstracto de Datos (Abstract Data Type, ADT)). Las variables
de estos tipos se llaman objetos. Llamar una función de la estructura sobre
un objeto es mandarle un mensaje al objeto.
Si bien encapsular datos y funciones en un TAD es un beneficio considerable
para organizar el código y prevenir la colisión de nombres, la OOP
(Programación Orientada a Objetos) es mucho más que esto.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 173
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Ocultando la implementación
Una librerı́a tı́pica de C consiste de una o más definiciones de estructuras
(struct) y funciones asociadas que actúan sobre dichas estructuras. En C++
las funciones se pueden asociar explı́citamente a esas estructuras poniendo
sus declaraciones dentro del scope de la estructura.
Pero hay una cuestión adicional que es hasta donde el programador debe
permitir que el usuario de la librerı́a manipule a la estructura. Si el usuario lee
las definiciones de la estructura puede por sı́ mismo manipular la estructura.
Ahora bien, si en algún momento el programador cambia la forma en que está
armada la estructura el código del usuario dejará de funcionar (“breaks the
code”).
Por ejemplo en la estructura Stack definida previamente el programador
podrı́a en el futuro decidir que es mejor alocar la memoria de a grandes
chunks de 100 elementos o más que alocar de a uno como está hecho en esa
implementación. Si el código del usuario depende de que la alocación se
haga de a un elemento, entonces al producirse el cambio de implementación
su código dejará de funcionar.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 174
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Ocultando la implementación (cont.)
En C esto se puede resolver parcialmente si el programador especifica en la
documentación de la librerı́a las funciones con las cuales el usuario de la
estructura debe manipular los objetos a través de las funciones provistas, y
hasta que punto puede usar directamente los datos almacenados en la
estructura. Pero esto es sólo un pacto entre el usuario y el programador, el
compilador no tiene forma de conocer estas reglas y prevenir al usuario de
manipular los objetos indebidamente.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 175
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Control de acceso a los miembros
El acceso a los miembros de una estructura en C++ se hace a través de 3
especificadores de acceso public, private y protected.
El keyword public quiere decir que todos los miembros siguientes son
accesibles para cualquiera, como ocurre con los miembros de una struct por
defecto. Por lo tanto, en el caso de una struct da lo mismo poner public al
principio o no. Las dos declaraciones siguientes son por lo tanto equivalentes
1
2
3
4
5
6
7
8
9
10
11
12
struct A {
int i,j;
float f;
void func();
};
struct A {
public:
int i,j;
float f;
void func();
};
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 176
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Control de acceso a los miembros (cont.)
La clave keyword private por el contrario, indica que los miembros
correspondientes sólo se pueden acceder desde código (es decir funciones)
de la misma clase.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
struct B {
private:
char j;
float f;
public:
int i;
void func();
};
void B::func() {
i = 0;
j = ’0’; // OK, access from a B function member
f = 0.0; // OK, idem
};
int main() {
B b;
b.i = 1; // OK, public
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 177
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
19
20
21
22
}
b.func(); // OK, public
b.j = ’1’; // Illegal, private
b.f = 1.0; // Illegal, private
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 178
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Control de acceso a los miembros (cont.)
• B::func() puede acceder a los miembros privados, porque es una funcion
•
•
•
•
de la clase, independientemente de si func() es a su vez privada o publica.
Una vez que se incluye el keyword private todas las declaraciones de
miembros dato y funciones son privadas, hasta la siguiente keyword
public.
Se pueden incluir tantas declaraciones private y public como sea
necesario.
Se pueden incluir dos declaraciones private o public seguidas.
protected es una mezcla de los dos, pero será explicado más adelante
cuando se explique el concepto de herencia.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 179
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Amistad (Friendship)
El keyword friend permite declarar que una función que no es miembro de la
estructura tenga acceso a todos los miembros de la misma.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Declaration (incomplete type specification):
struct X;
struct Y {
void f(X*);
};
struct X { // Definition
private:
int i;
public:
void initialize();
friend void g(X*, int); // Global friend
friend void Y::f(X*); // Struct member friend
friend struct Z; // Entire struct is a friend
friend void h();
};
void X::initialize() {
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 180
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
i = 0;
}
void g(X* x, int i) {
x->i = i;
}
void Y::f(X* x) {
x->i = 47;
}
struct Z {
private:
int j;
public:
void initialize();
void g(X* x);
};
void Z::initialize() {
j = 99;
}
void Z::g(X* x) {
x->i += j;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 181
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
46
47
48
49
50
51
52
53
54
55
56
void h() {
X x;
x.i = 100; // Direct data manipulation
}
int main() {
X x;
Z z;
z.g(&x);
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 182
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Anidamiento (nesting) y amistad
El estándar dice que en principio una clases anidada no tienen que ser
necesariamente amiga de la clase externa.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct E {
private:
int x;
struct B { };
struct I {
private:
B b; // error1: E::B is private
int y;
void f(E* p, int i) {
p->x = i; // error2: E::x is private
}
};
int g(I* p) { return p->y; } // error3: I::y is private
};
Sin embargo en la práctica el GCC da acceso a la clase externa a la clase
interna, pero no al revés. Es decir da error en 1 y 2, pero no en 3.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 183
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Object layout
Una de las condiciones de diseño de C++ fue que código válido en C deberı́a
compilar sin problemas en C++. Por esto las construcciones de tipo struct
tienen a todos sus miembros públicos.
Cuando el compilador organiza los datos dentro del objeto los guarda en
memoria en forma contigua, en el orden en el que están en la estructura.
Cuando introducimos especificadores de acceso, cada bloque de acceso
guarda sus miembros en forma contigua, pero los bloques de acceso pueden
estar entre sı́ puestos de cualquier forma (como si cada uno fuera una
estructura).
Las cuestiones de privilegios de acceso (acceso a los miembros privados y
públicos de la clase) tiene sentido sólo en el momento de compilación. Una
vez que el código fuente es convertido a código de máquina dos estructuras
que difieren sólo en cuanto a sus secciones private y public son
indistinguibles entre sı́, a menos del efecto discutido previamente de la
disposición en la memoria (object layout).
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 184
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Clases
Controlar el acceso a los miembros de una estructura es parte de lo que se
llama “ocultar la implementación” (implementation hiding). Esto es un
concepto clave en OOP.
En OOP se trata de ocultar lo más posible los miembros de la estructura, por
eso lo deseable serı́a que todos los miembros fueran privados por defecto.
Por eso en C++ existe un tipo de estructura alternativo class que es
completamente equivalente a las struct de C, pero donde todos los miembros
son por defecto private.
Todas estas clases son equivalentes
1
2
3
4
5
6
7
8
9
10
class A {
int i,j,k;
public:
double z;
void f();
};
struct B {
private:
int i,j,k;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 185
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
11
12
13
14
15
16
17
18
19
20
21
public:
double z;
void f();
};
struct C {
double z; // salvo por el object layout
void f();
private:
int i,j,k;
};
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 186
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Clases (cont.)
Vemos la clase Stash ahora con control de acceso. Todos los datos son
privados. La función inflate() también ya que sólo es usada internamente.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Stash {
int size; // Size of each space
int quantity; // Number of storage spaces
int next; // Next empty space
// Dynamically allocated array of bytes:
unsigned char* storage;
void inflate(int increase);
public:
void initialize(int size);
void cleanup();
int add(void* element);
void* fetch(int index);
int count();
};
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 187
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Clases (cont.)
En Stack ahora hacemos que toda la estructura Link sea privada o sea sólo es
accesible desde las funciones miembro de Stack.
1
2
3
4
5
6
7
8
9
10
11
12
13
class Stack {
struct Link {
void* data;
Link* next;
void initialize(void* dat, Link* nxt);
}* head;
public:
void initialize();
void push(void* dat);
void* peek();
void* pop();
void cleanup();
};
Notar que Link sigue siendo declarada como struct. De todas formas toda la
estructura es privada, o sea que desde fuera de Stack no se puede acceder.
Podrı́amos también declararla como clase, pero entonces deberı́amos
declarar friend a Stack.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 188
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Ocultando totalmente la implementación
Todavı́a uno podrı́a preguntarse si se puede ocultar aún más la
implementación. Que el usuario vea sólo la parte pública. Otra razón es evitar
la recompilación innecesaria. Una solución es usar punteros opacos, (aka
handles, en C++ se usa también el nombre Cheshire’s cat). Por ejemplo
podrı́amos ocultar completamente los detalles de Stash como está abajo. El
usuario sólo tiene acceso a stashwrapper.h.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Header file stashwrapper.h
class StashWrapper {
class Stash;
Stash *stash;
public:
void initialize(int size);
void cleanup();
int add(void* element);
void* fetch(int index);
int count();
};
// Implementation file stashwrapper.cpp
#include "stash.h"
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 189
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void StashWrapper::initialize(int size) {
stash=new Stash;
stash->initialize();
}
void StashWrapper::cleanup() {
stash->cleanup();
delete stash;
}
int StashWrapper::add(void* element) {
stash->add(element);
}
//. . .
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 190
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Inicialización y cleanup
Uno de los errores más comunes cuando se utilizan librerı́as es no inicializar
y destruir (cleanup) apropiadamente los objetos. En las librerı́as que hemos
descripto hasta ahora esto se hacı́a con funciones initialize() y cleanup().
Una de las ideas que C++ toma de la OOP es que estas operaciones de
inicialización y cleanup se hagan en forma automática.
1
2
3
4
5
6
7
8
9
10
class A {
// . . .
};
void f() {
A a; // a is created -> do initialization
// Usar a . . .
// . . .
// . . .
} // a is destroyed -> do cleanup
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 191
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Inicialización y cleanup (cont.)
Para esto debe haber dos funciones (una de inicialización y otra de cleanup)
que tengan nombres especiales ya que deben ser llamadas automáticamente
por el compilador. En C++ estas funciones se llaman el constructor y el
destructor de la clase. El constructor tiene el mismo nombre que la clase y
puede tener argumentos
1
2
3
4
5
6
7
8
9
10
11
class A {
public:
A() { /*. . .*/ }
// . . .
};
void f() {
A a; // a is created -> calls ctor A::A()
// Usar a . . .
// . . .
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 192
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
El constructor
• El ctor puede tener argumentos y puede haber varios constructores. Cual
•
•
•
•
•
de ellos es utilizado depende del contexto en el que es llamado.
El ctor que no tiene argumentos se llama el constructor por defecto.
No retorna ningún valor.
Debe ser declarado public para que pueda ser utilizado.
Puede ser privado pero entonces al menos debe tener una clase amiga ya
que si no no se podrı́a construir ningún objeto de la clase.
Si no declaramos ningún constructor entonces el compilador sintetiza
uno por nosotros y que es el constructor por defecto. Este ctor por
defecto no tiene cuerpo, lo único que hace es llamar a los ctores por
defecto de cada uno de los miembros (si son clases).
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 193
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
El destructor
• Asi como el constructor garantiza que se llama a la rutina de
•
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
inicialización, el destructor (abreviado dtor) se encarga de realizar las
tareas de cleanup.
Es llamado automáticamente cuando termina el scope del objeto.
// Constructors & destructors
#include <iostream>
using namespace std;
class Tree {
int height;
public:
Tree(int initialHeight); // Constructor
˜Tree(); // Destructor
void grow(int years);
void printsize();
};
Tree::Tree(int initialHeight) {
height = initialHeight;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 194
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Tree::˜Tree() {
cout << "inside Tree destructor" << endl;
printsize();
}
void Tree::grow(int years) {
height += years;
}
void Tree::printsize() {
cout << "Tree height is " << height << endl;
}
int main() {
cout << "before opening brace" << endl;
{
Tree t(12);
cout << "after Tree creation" << endl;
t.printsize();
t.grow(4);
cout << "before closing brace" << endl;
}
cout << "after closing brace" << endl;
} ///:˜
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 195
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
El destructor (cont.)
Salida del programa:
1
2
3
4
5
6
7
before opening brace
after Tree creation
Tree height is 12
before closing brace
inside Tree destructor
Tree height is 16
after closing brace
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 196
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Eliminación del bloque de definición
Es tı́pico de C tener que definir todas las variables al principio de un scope
(por ejemplo de una función). Por el contrario C++ promueve que las variables
se definan lo más cerca posible del punto en el que van a ser usadas. Esto se
pega con el uso automático de constructores, ya que puede ser que el
compilador no tenga toda la información como para llamar al constructor.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Defining variables anywhere
#include ". ./require.h"
#include <iostream>
#include <string>
using namespace std;
class G {
int i;
public:
G(int ii);
};
G::G(int ii) { i = ii; }
int main() {
cout << "initialization value? ";
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 197
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
17
18
19
20
21
22
}
int retval = 0;
cin >> retval;
require(retval != 0);
int y = retval + 3;
G g(y);
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 198
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Clase stash con ctor/dtor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// With constructors & destructors
class Stash {
int size; // Size of each space
int quantity; // Number of storage spaces
int next; // Next empty space
// Dynamically allocated array of bytes:
unsigned char* storage;
void inflate(int increase);
public:
Stash(int size);
˜Stash();
int add(void* element);
void* fetch(int index);
int count();
};
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 199
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Clase stash con ctor/dtor (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//: C06:Stash2.cpp {O}
// Constructors & destructors
#include "Stash2.h"
#include ". ./require.h"
#include <iostream>
#include <cassert>
using namespace std;
const int increment = 100;
Stash::Stash(int sz) {
size = sz;
quantity = 0;
storage = 0;
next = 0;
}
int Stash::add(void* element) {
if(next >= quantity) // Enough space left?
inflate(increment);
// Copy element into storage,
// starting at next empty space:
int startBytes = next * size;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 200
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
unsigned char* e = (unsigned char*)element;
for(int i = 0; i < size; i++)
storage[startBytes + i] = e[i];
next++;
return(next - 1); // Index number
}
void* Stash::fetch(int index) {
require(0 <= index, "Stash::fetch (-)index");
if(index >= next)
return 0; // To indicate the end
// Produce pointer to desired element:
return &(storage[index * size]);
}
int Stash::count() {
return next; // Number of elements in CStash
}
void Stash::inflate(int increase) {
require(increase > 0,
"Stash::inflate zero or negative increase");
int newQuantity = quantity + increase;
int newBytes = newQuantity * size;
int oldBytes = quantity * size;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 201
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
48
49
50
51
52
53
54
55
56
57
58
59
60
61
unsigned char* b = new unsigned char[newBytes];
for(int i = 0; i < oldBytes; i++)
b[i] = storage[i]; // Copy old to new
delete [ ](storage); // Old storage
storage = b; // Point to new memory
quantity = newQuantity;
}
Stash::˜Stash() {
if(storage != 0) {
cout << "freeing storage" << endl;
delete [ ]storage;
}
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 202
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Stack con ctor/dtor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// With constructors/destructors
#ifndef STACK3-H
#define STACK3-H
class Stack {
struct Link {
void* data;
Link* next;
Link(void* dat, Link* nxt);
˜Link();
}* head;
public:
Stack();
˜Stack();
void push(void* dat);
void* peek();
void* pop();
};
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 203
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Stack con ctor/dtor (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include "Stack3.h"
#include ". ./require.h"
using namespace std;
Stack::Link::Link(void* dat, Link* nxt) {
data = dat;
next = nxt;
}
Stack::Link::˜Link() { }
Stack::Stack() { head = 0; }
void Stack::push(void* dat) {
head = new Link(dat,head);
}
void* Stack::peek() {
require(head != 0, "Stack empty");
return head->data;
}
void* Stack::pop() {
if(head == 0) return 0;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 204
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
25
26
27
28
29
30
31
32
33
34
void* result = head->data;
Link* oldHead = head;
head = head->next;
delete oldHead;
return result;
}
Stack::˜Stack() {
require(head == 0, "Stack not empty");
} ///:˜
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 205
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Initialización de agregados
• Agregados son arreglos, estructuras y clases. Arreglos son de elementos
•
1
de un solo tipo, estructuras y clases puede ser de elementos de diferente
tipo.
Cuando se define un arreglo se puede inicializar con un juego de valores
entre llaves.
int a[5] = { 1, 2, 3, 4, 5 };
•
Inicializa cada uno de las posiciones de a en base a los valores entre
llaves.
Inicializa el primero a partir de 17 y todos los demás a partir del
constructor por defecto
int b[6] = {17};
• Conteo automático: automáticamente dimensiona c como c[4] a partir del
1
número de elementos entre llaves.
1
int c[ ] = { 1, 2, 3, 4 };
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 206
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Inicialización de estructuras
1
2
3
4
5
6
7
struct X {
int i;
float f;
char c;
};
X x1 = { 1, 2.2, ’c’ };
Se pueden inicializar un arreglo de X al mismo tiempo con doble llaves.
1
X x2[3] = { {1, 1.1, ’a’}, {2, 2.2, ’b’} };
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 207
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Sobrecarga de funciones
Vimos que el compilador decora los nombres de las funciones que
pertenecen a una clase (métodos) con el nombre de la clase
1
2
void f();
class X { void f(); };
Acá los nombres de las f no colisionan ya que son en realildad ::f() y X::f().
El compilador también decora los nombres de las funciones con el tipo de
sus argumentos de manera que
1
2
void print(char);
void print(float);
no colisionan entre sı́. (En C esto darı́a un error.) Esto se llama sobrecargar el
nombre de la función (en este caso print()). Sobrecargar quiere decir
entonces usar un mismo nombre para varias cosas diferentes.
Atención: NO se puede sobrecargar funciones por el valor de retorno.
1
2
int f(char c,double x);
char f(char c,double x); // ERROR!
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 208
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Sobrecarga de funciones (cont.)
Si compilamos y corremos la utilidad nm al archivo objeto nos da el nombre
interno de la función
1
2
3
4
5
[mstorti@galileo garage]$ nm try22.o
U --cxa-atexit
U --dso-handle
0000000000000010 T main
0000000000000000 T -Z1fcd <- This is int f(char c,double d)
El mangling _Z1fcd hace que el nombre del del archivo objeto sea único. El
lenguaje C no hace mangling, por eso no se puede sobrecargar.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 209
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Sobrecarga de funciones (cont.)
El nombre mangleado es difı́cil de identificar con respecto a la función
original. La opción nm -C permite obtener un nombre más legible. Esto es muy
útil cuando queremos buscar si una librerı́a tiene una dada función o no. Por
otro lado el mangling puede depender del sistema y del compilador, lo cual va
en contra de la portabilidad. Es decir no es posible transferir una librerı́a de
C++ compilado con un dado compilador a otro.
1
2
3
4
[mstorti@galileo
00000000000002d4
0000000000000000
[mstorti@galileo
garage]$ nm -C try22.o | grep f
t -GLOBAL--sub-I--Z1fcd
T f(char, double)
garage]$
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 210
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Sobrecarga de funciones (cont.)
Por lo tando, cuando definimos varios ctores, estamos sobrecargando el
nombre del ctor.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Stash {
int size; // Size of each space
int quantity; // Number of storage spaces
int next; // Next empty space
// Dynamically allocated array of bytes:
unsigned char* storage;
void inflate(int increase);
public:
Stash(int size); // Zero quantity
Stash(int size, int initQuantity);
˜Stash();
int add(void* element);
void* fetch(int index);
int count();
};
Ahora el ctor Stash(int,int) inicializa el tamaño del stash a partir del segundo
argumento. En cambio recordemos que Stash(int) dejaba al stash vacı́o.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 211
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Argumentos por default
Otra posibilidad es que los dos ctores previos sean el mismo con un
argumento por default para el tamaño
1
Stash(int size, int initQuantity = 0);
Entonces cuando se usa
1
Stash A(100), B(100, 2000);
En el primer llamado es equivalente a A(100,0)
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 212
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Constantes
Objetos de los cuales se supone que su valor no va a variar se pueden definir
como constantes
1
2
#define BUFSIZE 100 // en C
const int bufsize = 100; // en C++ (preferible)
En el caso de querer ponerlo en un header hay que usar
1
2
3
extern const int bufsize; // en un header
...
const int bufsize = 100; // en el .cpp
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 213
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Constantes (cont.)
Otro uso de const es para prometerle al compilador que no se va a modificar
esa variable, especialmente con punteros
1
const int* u;
Declara que u es un puntero a un int que es constante. De manera que si el
compilador detecta que estamos modificando al entero apuntado dará un
error
1
2
3
4
int x = 23;
const int* u;
u = &x;
*u = 55; // ERROR!
Notar que lo que es constante es el valor apuntado, no el puntero en si
mismo, el cual es modificado al hacer u = &x. Si queremos que el puntero sea
constante entonces hay que hacer
1
2
3
4
int x = 23, z=45;
int* const u = &x;
u = &z; // ERROR!
*u = 55; // OK, modifica x
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 214
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Constantes (cont.)
También pueden ser constantes las dos cosas, el puntero y el objeto
1
2
const int x = 32;
const int* const u = &x;
C/C++ chequea los tipos, tambien la constancia
1
2
3
4
5
6
int d = 1;
const int e = 2;
int* u = &d; // OK -- d not const
int* v = &e; // ERROR! -- e const
int* w = (int*)&e; // Legal but bad practice
const int* z = &e; // OK
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 215
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Punteros a arreglos constantes de caracteres
1
char* cp = "Hello world"; // warning!!
Como el arreglo de caracteres no fue alocado con new, es constante, o sea
que debe ser declarado ası́
1
const char* cp = "Hello world"; // OK
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 216
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Const en argumentos de funciones
1
2
3
void f(const int i) {
i++; // Illegal -- compile-time error
}
De todas formas no tiene demasiado sentido porque i es pasado por copia.
Pero sı́ tiene sentido cuando se pasan argumentos por referencia o por
puntero
1
2
3
4
5
6
7
void f(const int *p) {
*p = 23; // ERROR!
}
void g(const int &x) {
x = 23; // ERROR!
}
Recordar que pasar por puntero o referencia puede ser para modificar el valor
o también para evitar la copia. Incluyendo el const permite pasar los
argumentos en forma eficiente, pero evitando que accidentalmente se
modifique el objeto.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 217
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Const en clases
Si se quiere tener parámetros de una clase, que son constantes, entonces no
sólo hay que ponerle const, sino también static que quiere decir que ese
miembro es el mismo para todos los objetos de la clase. De esa forma actúa
como una variable global pero protegida por el scope de la clase. Sirve para
definir opciones de la clase para poder ser inspeccionadas o modificadas por
el usuario.
1
2
3
4
5
6
7
8
9
class StringStack {
static const int size = 100;
const string* stack[size];
int index;
public:
StringStack();
void push(const string* s);
const string* pop();
};
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 218
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Objetos const y funciones de la clase
Si tenemos una clase A entonces al declarar funciones ası́
1
2
void f(const A &a);
void g(const A *p);
estamos diciendo que no van a modificar el argumento correspondiente.
¿Como hacer lo mismo con los métodos de la clase para decir que no
modifican al objeto que son aplicados (*this)?
1
2
3
4
5
6
class A {
public:
void f() const;
void g();
};
void A::f() const { /* . . . */ }
Quiere decir que si hacemos
1
2
A a;
a.f();
podemos estar seguros que la llamada a f() no modifica a a.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 219
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Objetos const y funciones de la clase (cont.)
Entonces el compilador chequea que si un objeto es const sólo pueden ser
llamados sobre el funciones y métodos que no lo modifican, es decir que lo
declaran const.
1
2
3
4
5
6
7
8
9
10
11
12
const A a1;
a1.f(); // OK, f es const
a1.g(); // ERROR, g no es const
void h(A &a) {
a.g(); // OK a no es const
}
void h2(const A &a) {
a.f(); // OK, f es const
a.g(); // ERROR, g no es const
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 220
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Chapter 5
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 221
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Funciones inline
• Cada vez que hay una llamada a función hay un costo adicional de pasar
•
•
•
•
los argumentos por el stack a la función y hacer un jump de assemble.
Para evitar esto podemos usar el keyword inline que indica al compilador
que queremos que el código de esa función sea replicado en cada punto
en que lo llamamos.
La ventaja, como dijimos, es la eficiencia, se evita el mecanismo de
llamado a función en assemble.
La desventaja es que el código binario de la función aparece duplicado en
cada punto, con lo cual el ejecutable se hace más grande. También
implica que el código de la función debe ser visible (o sea estar en el
header) en cada punto en que queremos que sea implementado inline.
El keyword inline es una sugerencia para el compilador. El compilador
puede después hacer la función realmente inline o no. A veces puede
hacerla no inline porque es muy compleja (e.g. tiene lazos) o porque en
algún punto se toma la dirección de la función.
Funciones definidas en la misma clase (y por lo tanto en el header
normalmente) son candidatas a ser promovidas a inline por el compilador.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 222
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Funciones inline (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// file: a.hpp
// ‘max’ es explicitamente inline
// (Notar que si no es inline daria error
// al linkeditar por multiple definicion de max())
inline double max(double x,double y) {
return (x>y ? x : y);
}
class A {
private:
int maxsize;
public:
// Accessors: automaticamente inline
int get-maxsize() { return maxsize; }
void set-maxsize(int maxsz) { maxsize=maxsz; }
//. . .
};
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 223
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Funciones inline (cont.)
Otra forma que habrı́a para evitar el llamado a funciones serı́a no definir la
función sino que en cada punto que se usa incluir explı́citamente su código.
Para evitar esto una forma que existı́a en C para crear las funciones inline era
definir macros, por ejemplo
1
#define MAX(x,y) (x>y ? x : y)
Recordar que eso hace que en cada punto del código final se reemplaze la
llamada a MAX por la expansión del macro.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 224
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Funciones inline (cont.)
• OJO, como pasa en general con los macros son peligrosos, Por ejemplo
1 int l = MAX(j++,k);
tiene el efecto indeseado que incrementa dos veces a j.
Otro problema es con la precedencia de los operadores.
•
1 #define SQUARE(x) x*x
2 . . .
3 // Hace a=11!!
4 a = SQUARE(5+1)
ya que es completamente equivalente a
1
a = 5+1*5+1
La definición apropiada se obtiene protegiendo los argumentos con
paréntesis.
1
#define SQUARE(x) (x)*(x)
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 225
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Especificaciones de linkedicion
Cuando declaramos una función, digamos
1
void f(int x, char c);
dijimos que internamente el compilador la decora (también se llama a esto
mangling) a, por ejemplo, _Z1fcd. Esto es a efectos de poder después
sobrecargar la función. Ahora bien, si queremos usar una librerı́a de C,
entonces ésta cuando fue compilada no hizo el mangling, y por lo tanto
cuando se va a linkeditar no la va a encontrar. Para eso hay que usar el
keyword extern al declarar la función
1
extern "C" void f(int x, char c);
Esto le dice al compilador que no decore el nombre de esa función. Notar que
por lo tanto esa función no puede ser sobrecargada.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 226
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Especificaciones de linkedicion (cont.)
Como las declaraciones de las librerı́as estarán en headers de esas librerı́as,
como hacemos para ponerle un extern "C" a cada una de las funciones del
header? Basta con hacerlo externo al include
1
2
3
extern "C" {
#include <clibheader.h>
}
Muchos de los headers de librerı́as de C importantes ya vienen con este tipo
de declaraciones de forma de poder ser llamados desde C++, por ejemplo
todas las de la libc.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 227
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Referencias en C++
Vimos el concepto de referencia, básicamente son punteros inteligentes que
se autodereferencian.
Se pueden implementar funciones que modifican sus argumentos mediante
punteros
1
2
3
4
5
6
void inc(int *x) {
*x = *x + 1,
}
...
int a=2;
inc(&a); // hace a=3
pero son engorrosos porque hay que ir derereferenciando el puntero. Con
referencias es mucho mejor,
1
2
3
4
5
6
void inc(int &x) {
x = x + 1,
}
...
int a=2;
inc(a); // hace a=3
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 228
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Referencias en C++ (cont.)
Otro uso es para crear aliases locales para modificar una parte de un
contenedor más grande, por ejemplo un arreglo de varias dimensiones
(también puede ser con los contenedores de las STL)
1
2
3
4
5
6
7
8
9
10
11
class A {
// . . . .
void f(); // modifica a *this
};
// arreglo multidimensional de A’s
A av[100][100][100];
// Un elemento particular de av
int i,j,k;
//. . .
av[i][j][k].f();
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 229
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Referencias en C++ (cont.)
Si queremos manipular mucho a ese elemento particular de av entonces en
cada punto hay que poner av[i][j][k]. Si fuera un tipo simple, como un int o
un double, entonces podrı́amos crear una copia local y después pisar el valor
en av
1
2
3
4
5
6
7
// arreglo multidimensional de A’s
int v[100][100][100];
// Un elemento particular de av
int x = v[i][j][k];
// . . . hace calculos con x
// Pisa el valor en av
v[i][j][k] = x;
Pero si A es una clase complicada esto implica hacer una copia del objeto, lo
cual es ineficiente y incluso puede ser que no podamos hacer copias del
objeto.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 230
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Referencias en C++ (cont.)
De nuevo, una posibilidad es usar macros
1
2
3
4
5
6
7
// arreglo multidimensional de A’s
A av[100][100][100];
// Un elemento particular de av
int i,j,k;
#define AIJK av[i][j][k]
//. . .
AIJK.f();
Como siempre, los macros son peligrosos y hay que tratar de no usarlos.
Además cada vez que llamamos a AIJK estamos haciendo una cuenta con
i,j,k para encontrar la posición correspondiente en v.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 231
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Referencias en C++ (cont.)
Una posibilidad es usar punteros
1
2
3
4
5
6
7
// arreglo multidimensional de A’s
A av[100][100][100];
// Un elemento particular de av
int i,j,k;
A *ap = &av[i][j][k];
ap->f();
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 232
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Referencias en C++ (cont.)
Esto es eficiente, y compacto pero hay que andar dereferenciando ap. Todavı́a
mejor es usar referencias
1
2
3
4
5
6
7
// arreglo multidimensional de A’s
A av[100][100][100];
// Un elemento particular de av
int i,j,k;
A &a = av[i][j][k];
a.f();
Es eficiente, limpio, y a se manipula como un objeto más de la clase.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 233
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Reglas para las referencias
• Las referencias deben ser inicializadas cuando son creadas
1 A &a = av[i][j][k]; // OK
2
3 A &a; // ERROR (No incluye inicializacion)
4 a = av[i][j][k];
• Una vez que una referencia apunta a un objeto, no se lo puede hacer
apuntar a otro
1
2
3
4
A &a = av[i][j][k];
a = av[l][m][n]; // compila OK, pero no reposiciona
// la referencia, simplemente hace
// una copia del elemento l,m,n al i,j,k
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 234
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Reglas para las referencias (cont.)
Lo que SI se puede hacer es ir creando referencias con el mismo nombre a
diferentes objetos
1
2
3
4
5
6
7
8
for (int i=0; i<N; i++) {
for (int j=0; j<N; j++) {
for (int k=0; k<N; k++) {
A &a = av[i][j][k];
// manipula av[i][j][k] a través de a
}
}
}
• No se puede hacer una referencia a NULL.
• Hacer referencias es muy eficiente, igual que con punteros.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 235
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Paso por referencia y por copia
Normalmente uno escribe el paso de argumentos por copia
1
void f(A a, B b) {. . .}
Esto es ineficiente y además requiere que las clases A, B implementen el
constructor por copia A(A&), B(B&) (en general se le llama X(X&)).
1
2
3
4
class A {
//. . .
A(A&) { . . . } // Constructor por copia
};
Para evitar esto ya mencionamos que se puede pasar por referencia
1
void f(A &a, B &b) {. . .}
Si la función no va a modificar los argumentos es todavı́a mejor declarar a las
referencias como const
1
void f(const A &a,const B &b) {. . .}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 236
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
El constructor por copia
• Vimos que al pasar objetos a funciones por copia se llama al constructor
•
•
•
1
2
3
4
5
6
7
por copia.
Si la clase no define al constructor por copia el compilador sintetiza uno
por nosotros (haciendo copia bit-a-bit).
Esto se llama una shallow copy (por contraposición con una deep copy) y
puede traer problemas, sobre todo si el objeto contiene punteros a áreas
de almacenamiento dinámico alocados con new.
O bien hay que implementar el constructor por copia haciendo la deep
copy o bien hay que prohibirlo declarando al constructor por copia
privado
class A {
private:
A(A&) {}
}
void f(A a) { // ERROR, llama al ctor por copia
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 237
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Sobrecarga de operadores
• Sobrecarga de operadores es simplemente un aditivo sintáctico (sintactic
•
•
•
•
sugar) para hacer llamadas a funciones de la clase en forma más
compacta.
Los nombres de los operadores son operator@ donde @ puede ser algunos
de los operadores usuales, matemáticos (+, -, *, /), de indexación [], (),
incremento ++, --, acumulación (+=, -=, *=, /=), lógicos ||, &&, etc...
Hay operadores unarios y binarios. A veces el mismo operador puede ser
unario o binario dependiendo del contexto (por ejemplo *
(dereferenciación como unario, producto como binario), +, -).
Cuál de los operadores es llamado y sobre que objetos es a veces un
poco difı́cil de discernir.
Pueden ser métodos de la clase o pueden ser funciones globales
(declaradas friend)
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 238
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Sobrecarga de operadores (cont.)
En el caso de operadores unarios, el objeto al cual se aplica el operador pasa
a ser *this
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class A {
A operator*(const A& right) { . . . } // producto (1)
};
class HandleToA {
A &operator*() { . . . } // dereferenciacion (2)
};
A a1, a2, a3;
HandleToA p;
a1 = a2*a3; // llama a (1) con *this = a2,
// right = a3 y el valor de retorno
// es asignado a a1
a1 = *p; // llama a (2) con *this = p
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 239
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Sobrecarga de operadores (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;
class Integer {
int i;
public:
Integer(int ii) : i(ii) {}
const Integer
operator+(const Integer& rv) const {
cout << "operator+" << endl;
return Integer(i + rv.i);
}
Integer&
operator+=(const Integer& rv) {
cout << "operator+=" << endl;
i += rv.i;
return *this;
}
};
int main() {
cout << "built-in types:" << endl;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 240
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
23
24
25
26
27
28
}
int i = 1, j = 2, k = 3;
k += i + j;
cout << "user-defined types:" << endl;
Integer ii(1), jj(2), kk(3);
kk += ii + jj;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 241
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Sobrecarga de operadores (cont.)
• Se pueden sobrecargar buena parte de los operadores que ya existen en C.
• No se pueden inventar nuevos operadores (e.g. usar ** para la
•
exponenciación, como en Fortran).
No se puede cambiar la regla de precedencia de los operadores.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 242
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Sobrecarga de operadores unarios
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;
// Non-member functions:
class Integer {
long i;
Integer* This() { return this; }
public:
Integer(long ll = 0) : i(ll) {}
// No side effects takes const& argument:
friend const Integer&
operator+(const Integer& a);
friend const Integer
operator-(const Integer& a);
friend const Integer
operator˜(const Integer& a);
friend Integer*
operator&(Integer& a);
friend int
operator!(const Integer& a);
// Side effects have non-const& argument:
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 243
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// Prefix:
friend const Integer&
operator++(Integer& a);
// Postfix:
friend const Integer
operator++(Integer& a, int);
// Prefix:
friend const Integer&
operator--(Integer& a);
// Postfix:
friend const Integer
operator--(Integer& a, int);
};
// Global operators:
const Integer& operator+(const Integer& a) {
cout << "+Integer\n";
return a; // Unary + has no effect
}
const Integer operator-(const Integer& a) {
cout << "-Integer\n";
return Integer(-a.i);
}
const Integer operator˜(const Integer& a) {
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 244
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
cout << "˜Integer\n";
return Integer(˜a.i);
}
Integer* operator&(Integer& a) {
cout << "&Integer\n";
return a.This(); // &a is recursive!
}
int operator!(const Integer& a) {
cout << "bang Integer\n";
return !a.i;
}
// Prefix; return incremented value
const Integer& operator++(Integer& a) {
cout << "++Integer\n";
a.i++;
return a;
}
// Postfix; return the value before increment:
const Integer operator++(Integer& a, int) {
cout << "Integer++\n";
Integer before(a.i);
a.i++;
return before;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 245
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
}
// Prefix; return decremented value
const Integer& operator--(Integer& a) {
cout << "--Integer\n";
a.i--;
return a;
}
// Postfix; return the value before decrement:
const Integer operator--(Integer& a, int) {
cout << "Integer--\n";
Integer before(a.i);
a.i--;
return before;
}
// Show that the overloaded operators work:
void f(Integer a) {
+a;
-a;
˜a;
Integer* ip = &a;
!a;
++a;
a++;
--a;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 246
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
a--;
}
// Member functions (implicit ‘‘this’’):
class Byte {
unsigned char b;
public:
Byte(unsigned char bb = 0) : b(bb) {}
// No side effects: const member function:
const Byte& operator+() const {
cout << "+Byte\n";
return *this;
}
const Byte operator-() const {
cout << "-Byte\n";
return Byte(-b);
}
const Byte operator˜() const {
cout << "˜Byte\n";
return Byte(˜b);
}
Byte operator!() const {
cout << "bang Byte\n";
return Byte(!b);
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 247
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
}
Byte* operator&() {
cout << "&Byte\n";
return this;
}
// Side effects: non-const member function:
const Byte& operator++() { // Prefix
cout << "++Byte\n";
b++;
return *this;
}
const Byte operator++(int) { // Postfix
cout << "Byte++\n";
Byte before(b);
b++;
return before;
}
const Byte& operator--() { // Prefix
cout << "--Byte\n";
--b;
return *this;
}
const Byte operator--(int) { // Postfix
cout << "Byte--\n";
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 248
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
Byte before(b);
--b;
return before;
}
};
void g(Byte b) {
+b;
-b;
˜b;
Byte* bp = &b;
!b;
++b;
b++;
--b;
b--;
}
int main() {
Integer a;
f(a);
Byte b;
g(b);
} ///:˜
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 249
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Sobrecarga de operadores unarios (cont.)
Operadores ++ y -- prefijo y postfijo: Recordemos que hay dos versiones del
operador ++, cuando hacemos i++ y ++i, ambos se pueden sobrecargar con el
operador operator++() pero como hacer para diferenciarlos? El prefijo es
operator++() y el postfijo es operator++(int). Notar que el argumento int para
el postfijo no se usa y por lo tanto no hace falta pasarle el argumento dummy
correspondiente.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 250
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Sobrecarga de operadores binarios
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Non-member overloaded operators
#include <iostream>
// Non-member functions:
class Integer {
long i;
public:
Integer(long ll = 0) : i(ll) {}
// Operators that create new, modified value:
friend const Integer
operator+(const Integer& left,
const Integer& right);
friend const Integer
operator-(const Integer& left,
const Integer& right);
friend const Integer
operator*(const Integer& left,
const Integer& right);
friend const Integer
operator/(const Integer& left,
const Integer& right);
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 251
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
friend const Integer
operator%(const Integer& left,
const Integer& right);
friend const Integer
operatorˆ(const Integer& left,
const Integer& right);
friend const Integer
operator&(const Integer& left,
const Integer& right);
friend const Integer
operator|(const Integer& left,
const Integer& right);
friend const Integer
operator<<(const Integer& left,
const Integer& right);
friend const Integer
operator>>(const Integer& left,
const Integer& right);
// Assignments modify & return lvalue:
friend Integer&
operator+=(Integer& left,
const Integer& right);
friend Integer&
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 252
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
operator-=(Integer& left,
const Integer& right);
friend Integer&
operator*=(Integer& left,
const Integer& right);
friend Integer&
operator/=(Integer& left,
const Integer& right);
friend Integer&
operator%=(Integer& left,
const Integer& right);
friend Integer&
operatorˆ=(Integer& left,
const Integer& right);
friend Integer&
operator&=(Integer& left,
const Integer& right);
friend Integer&
operator|=(Integer& left,
const Integer& right);
friend Integer&
operator>>=(Integer& left,
const Integer& right);
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 253
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
friend Integer&
operator<<=(Integer& left,
const Integer& right);
// Conditional operators return true/false:
friend int
operator==(const Integer& left,
const Integer& right);
friend int
operator!=(const Integer& left,
const Integer& right);
friend int
operator<(const Integer& left,
const Integer& right);
friend int
operator>(const Integer& left,
const Integer& right);
friend int
operator<=(const Integer& left,
const Integer& right);
friend int
operator>=(const Integer& left,
const Integer& right);
friend int
operator&&(const Integer& left,
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 254
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
const Integer& right);
friend int
operator| |(const Integer& left,
const Integer& right);
// Write the contents to an ostream:
void print(std::ostream& os) const { os << i; }
};
#endif // INTEGER-H ///:˜
//: C12:Integer.cpp {O}
// Implementation of overloaded operators
#include "Integer.h"
#include ". ./require.h"
const Integer
operator+(const Integer& left,
const Integer& right) {
return Integer(left.i + right.i);
}
const Integer
operator-(const Integer& left,
const Integer& right) {
return Integer(left.i - right.i);
}
const Integer
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 255
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
operator*(const Integer& left,
const Integer& right) {
return Integer(left.i * right.i);
}
const Integer
operator/(const Integer& left,
const Integer& right) {
require(right.i != 0, "divide by zero");
return Integer(left.i / right.i);
}
const Integer
operator%(const Integer& left,
const Integer& right) {
require(right.i != 0, "modulo by zero");
return Integer(left.i % right.i);
}
const Integer
operatorˆ(const Integer& left,
const Integer& right) {
return Integer(left.i ˆ right.i);
}
const Integer
operator&(const Integer& left,
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 256
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
const Integer& right) {
return Integer(left.i & right.i);
}
const Integer
operator|(const Integer& left,
const Integer& right) {
return Integer(left.i | right.i);
}
const Integer
operator<<(const Integer& left,
const Integer& right) {
return Integer(left.i << right.i);
}
const Integer
operator>>(const Integer& left,
const Integer& right) {
return Integer(left.i >> right.i);
}
// Assignments modify & return lvalue:
Integer& operator+=(Integer& left,
const Integer& right) {
if(&left == &right) {/* self-assignment */}
left.i += right.i;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 257
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
return left;
}
Integer& operator-=(Integer& left,
const Integer& right) {
if(&left == &right) {/* self-assignment */}
left.i -= right.i;
return left;
}
Integer& operator*=(Integer& left,
const Integer& right) {
if(&left == &right) {/* self-assignment */}
left.i *= right.i;
return left;
}
Integer& operator/=(Integer& left,
const Integer& right) {
require(right.i != 0, "divide by zero");
if(&left == &right) {/* self-assignment */}
left.i /= right.i;
return left;
}
Integer& operator%=(Integer& left,
const Integer& right) {
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 258
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
require(right.i != 0, "modulo by zero");
if(&left == &right) {/* self-assignment */}
left.i %= right.i;
return left;
}
Integer& operatorˆ=(Integer& left,
const Integer& right) {
if(&left == &right) {/* self-assignment */}
left.i ˆ= right.i;
return left;
}
Integer& operator&=(Integer& left,
const Integer& right) {
if(&left == &right) {/* self-assignment */}
left.i &= right.i;
return left;
}
Integer& operator|=(Integer& left,
const Integer& right) {
if(&left == &right) {/* self-assignment */}
left.i |= right.i;
return left;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 259
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
Integer& operator>>=(Integer& left,
const Integer& right) {
if(&left == &right) {/* self-assignment */}
left.i >>= right.i;
return left;
}
Integer& operator<<=(Integer& left,
const Integer& right) {
if(&left == &right) {/* self-assignment */}
left.i <<= right.i;
return left;
}
// Conditional operators return true/false:
int operator==(const Integer& left,
const Integer& right) {
return left.i == right.i;
}
int operator!=(const Integer& left,
const Integer& right) {
return left.i != right.i;
}
int operator<(const Integer& left,
const Integer& right) {
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 260
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
return left.i < right.i;
}
int operator>(const Integer& left,
const Integer& right) {
return left.i > right.i;
}
int operator<=(const Integer& left,
const Integer& right) {
return left.i <= right.i;
}
int operator>=(const Integer& left,
const Integer& right) {
return left.i >= right.i;
}
int operator&&(const Integer& left,
const Integer& right) {
return left.i && right.i;
}
int operator| |(const Integer& left,
const Integer& right) {
return left.i | | right.i;
} ///:˜
//: C12:IntegerTest.cpp
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 261
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
//{L} Integer
#include "Integer.h"
#include <fstream>
using namespace std;
ofstream out("IntegerTest.out");
void h(Integer& c1, Integer& c2) {
// A complex expression:
c1 += c1 * c2 + c2 % c1;
#define TRY(OP) \
out << "c1 = "; c1.print(out); \
out << ", c2 = "; c2.print(out); \
out << "; c1 " #OP " c2 produces "; \
(c1 OP c2).print(out); \
out << endl;
TRY(+) TRY(-) TRY(*) TRY(/)
TRY(%) TRY(ˆ) TRY(&) TRY(|)
TRY(<<) TRY(>>) TRY(+=) TRY(-=)
TRY(*=) TRY(/=) TRY(%=) TRY(ˆ=)
TRY(&=) TRY(|=) TRY(>>=) TRY(<<=)
// Conditionals:
#define TRYC(OP) \
out << "c1 = "; c1.print(out); \
out << ", c2 = "; c2.print(out); \
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 262
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
out << "; c1 " #OP " c2 produces "; \
out << (c1 OP c2); \
out << endl;
TRYC(<) TRYC(>) TRYC(==) TRYC(!=) TRYC(<=)
TRYC(>=) TRYC(&&) TRYC(| |)
}
int main() {
cout << "friend functions" << endl;
Integer c1(47), c2(9);
h(c1, c2);
} ///:˜
//: C12:Byte.h
// Member overloaded operators
#ifndef BYTE-H
#define BYTE-H
#include ". ./require.h"
#include <iostream>
// Member functions (implicit ‘‘this’’):
class Byte {
unsigned char b;
public:
Byte(unsigned char bb = 0) : b(bb) {}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 263
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
// No side effects: const member function:
const Byte
operator+(const Byte& right) const {
return Byte(b + right.b);
}
const Byte
operator-(const Byte& right) const {
return Byte(b - right.b);
}
const Byte
operator*(const Byte& right) const {
return Byte(b * right.b);
}
const Byte
operator/(const Byte& right) const {
require(right.b != 0, "divide by zero");
return Byte(b / right.b);
}
const Byte
operator%(const Byte& right) const {
require(right.b != 0, "modulo by zero");
return Byte(b % right.b);
}
const Byte
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 264
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
operatorˆ(const Byte& right) const {
return Byte(b ˆ right.b);
}
const Byte
operator&(const Byte& right) const {
return Byte(b & right.b);
}
const Byte
operator|(const Byte& right) const {
return Byte(b | right.b);
}
const Byte
operator<<(const Byte& right) const {
return Byte(b << right.b);
}
const Byte
operator>>(const Byte& right) const {
return Byte(b >> right.b);
}
// Assignments modify & return lvalue.
// operator= can only be a member function:
Byte& operator=(const Byte& right) {
// Handle self-assignment:
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 265
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
if(this == &right) return *this;
b = right.b;
return *this;
}
Byte& operator+=(const Byte& right) {
if(this == &right) {/* self-assignment */}
b += right.b;
return *this;
}
Byte& operator-=(const Byte& right) {
if(this == &right) {/* self-assignment */}
b -= right.b;
return *this;
}
Byte& operator*=(const Byte& right) {
if(this == &right) {/* self-assignment */}
b *= right.b;
return *this;
}
Byte& operator/=(const Byte& right) {
require(right.b != 0, "divide by zero");
if(this == &right) {/* self-assignment */}
b /= right.b;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 266
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
return *this;
}
Byte& operator%=(const Byte& right) {
require(right.b != 0, "modulo by zero");
if(this == &right) {/* self-assignment */}
b %= right.b;
return *this;
}
Byte& operatorˆ=(const Byte& right) {
if(this == &right) {/* self-assignment */}
b ˆ= right.b;
return *this;
}
Byte& operator&=(const Byte& right) {
if(this == &right) {/* self-assignment */}
b &= right.b;
return *this;
}
Byte& operator|=(const Byte& right) {
if(this == &right) {/* self-assignment */}
b |= right.b;
return *this;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 267
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
Byte& operator>>=(const Byte& right) {
if(this == &right) {/* self-assignment */}
b >>= right.b;
return *this;
}
Byte& operator<<=(const Byte& right) {
if(this == &right) {/* self-assignment */}
b <<= right.b;
return *this;
}
// Conditional operators return true/false:
int operator==(const Byte& right) const {
return b == right.b;
}
int operator!=(const Byte& right) const {
return b != right.b;
}
int operator<(const Byte& right) const {
return b < right.b;
}
int operator>(const Byte& right) const {
return b > right.b;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 268
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
int operator<=(const Byte& right) const {
return b <= right.b;
}
int operator>=(const Byte& right) const {
return b >= right.b;
}
int operator&&(const Byte& right) const {
return b && right.b;
}
int operator| |(const Byte& right) const {
return b | | right.b;
}
// Write the contents to an ostream:
void print(std::ostream& os) const {
os << "0x" << std::hex << int(b) << std::dec;
}
};
#endif // BYTE-H ///:˜
//: C12:ByteTest.cpp
#include "Byte.h"
#include <fstream>
using namespace std;
ofstream out("ByteTest.out");
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 269
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
void k(Byte& b1, Byte& b2) {
b1 = b1 * b2 + b2 % b1;
#define TRY2(OP) \
out << "b1 = "; b1.print(out); \
out << ", b2 = "; b2.print(out); \
out << "; b1 " #OP " b2 produces "; \
(b1 OP b2).print(out); \
out << endl;
b1 = 9; b2 = 47;
TRY2(+) TRY2(-) TRY2(*) TRY2(/)
TRY2(%) TRY2(ˆ) TRY2(&) TRY2(|)
TRY2(<<) TRY2(>>) TRY2(+=) TRY2(-=)
TRY2(*=) TRY2(/=) TRY2(%=) TRY2(ˆ=)
TRY2(&=) TRY2(|=) TRY2(>>=) TRY2(<<=)
TRY2(=) // Assignment operator
// Conditionals:
#define TRYC2(OP) \
out << "b1 = "; b1.print(out); \
out << ", b2 = "; b2.print(out); \
out << "; b1 " #OP " b2 produces "; \
out << (b1 OP b2); \
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 270
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
out << endl;
b1 = 9; b2 = 47;
TRYC2(<) TRYC2(>) TRYC2(==) TRYC2(!=) TRYC2(<=)
TRYC2(>=) TRYC2(&&) TRYC2(| |)
// Chained assignment:
Byte b3 = 92;
b1 = b2 = b3;
}
int main() {
out << "member functions:" << endl;
Byte b1(47), b2(9);
k(b1, b2);
} ///:˜
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 271
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Sobrecarga de operadores binarios (cont.)
• En los operadores de acumulación (e.g. operator+=) se tiene que
1 Integer& operator+=(Integer& left,
2
const Integer& right) {
3
if(&left == &right) {/* self-assignment */}
4
left.i += right.i;
5
return left;
6 }
7 // . . .
8 Integer R,L;
9 L += R;
Tenemos que left es L, right es R. Hay que tener cuidado porque el L y R
podrı́an ser el mismo objeto, por ejemplo si hacemos
1
2
Integer A;
A += A;
Lo mismo pasa con el operador de asignación operator=(). A esto se le
llama chequear por autoasignación. Sobre todo si hay componentes
apuntadas por punteros.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 272
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Chapter
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 273
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Otros operadores que se pueden sobrecargar
• operator[]: Se usa normalmente para emular lo que ocurre al indexar un
•
•
vector por un entero. En las STL se usa en las clases vector<> y map<>
operator(): Se usa para emular que el objeto actúa como una función
(functor).
operator*, operator->: Se utilizan para emular el comportamiento de los
punteros (por ejemplo los smart pointers). En las STL se usan para los
iterators de los diferentes contenedores.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 274
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Creación dinámica de objetos
Las variables de un programa pueden ser alocados en tres formas diferentes
y normalmente viven en secciones diferentes de memoria
• Objetos globales y estáticos son alocados en el momento de arrancar el
•
•
programa y viven durante toda la duración del mismo.
Objetos dinámicos son alocados al entrar en el scope correspondiente.
La alocación se hace en el stack.
Objetos pueden ser alocados y desalocados en cualquier momento
(responsabilidad del programador) en el heap.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 275
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Uso de la memoria dinámica en C
En C la alocación en el heap se hace con las funciones malloc() y free(). El
uso básico para objetos en C serı́a ası́
1
2
3
4
5
6
7
struct A { };
A *p = (A*)malloc(sizeof(A));
A-initialize(p);
// . . . . usa *p
A-destroy(p);
free(p);
Hay varios puntos donde esto puede fallar, por un error del programador:
•
•
•
•
•
No alocar apropiadamente la memoria apropiada para el objeto.
No convertir el puntero al tipo apropiado.
No inicializar el objeto.
No destruir el objeto.
No liberar la memoria alocada.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 276
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Uso de la memoria dinámica en C++
En C++ se trata que todas estas acciones sean hechas en lo posible en forma
automática por el operador. Para esto las funciones malloc() y free() (que
después de todo son funciones de librerı́a es decir que no son parte del
lenguaje) son reemplazadas por operadores intrı́nsecos del lenguaje: new y
delete.
1
2
3
A *p = new A;
// . . . usa *p
delete p;
new A se encarga de alocar el espacio apropiado (sizeof(A), castear al tipo
correcto (A*) e inicializar (llamar al constructor).
delete p se encarga de llamar al destructor y liberar la memoria alocada.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 277
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Uso de la memoria dinámica en C++ (cont.)
Como new se encarga de la inicialización, también se puede llamar con
cualquier otro constructor, además del ctor por defecto
1
A *p = new A(x,y,z);
También se pueden alocar arreglos de objetos
1
A *av = new A[100];
En este caso el compilador se encarga de alocar el espacio para los 100
objetos y llamar al constructor por defecto sobre cada uno de ellos. No hay
forma de inicializar arreglos con un constructor que no sea el ctor por defecto.
Recordar que para arreglos se puede inicializar explı́citamente cada objeto
(pero no todos al mismo tiempo)
1
A av[4] = {1,2,3}
Para el cuarto (av[3]) usa el constructor por defecto.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 278
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Porqué usar new y no arreglos
1
2
3
4
5
6
7
A av1[20]; // OK la dimension es una cte
const int m=100;
A av1[m]; // OK la dimension es una cte
int n=100;
A a[n]; // ERROR
El último deberı́a dar error de compilación aunque dependiendo del
compilador puede que no lo de (serı́a una extensión del compilador). De
todas formas siempre es más restrictivo que alocar con new porque el arreglo
es desalocado y destruido cuando termina su scope.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 279
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Memory exhaust
Qué ocurre si se acaba la memoria? En viejos compiladores new retornaba un
puntero nulo. En el estándar actual lanza una excepción de tipo bad_alloc().
Por compatibilidad con la versión antigua se le puede usar new(std::nothrow)
que emula el primer comportamiento.
1
2
3
4
5
6
7
8
9
10
11
12
13
try { // version ‘throw’
int *p = new int[N];
// alocacion exitosa, usar p. . .
} catch(bad-alloc) {
cout << "error" << endl;
break;
}
// version ‘nothrow’
int *p = new(std::nothrow) int[N];
if (!p) {
// error. . .
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 280
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Composición
Hasta ahora vimos clases/estructuras que se construyen a partir de tipos
básicos usando composición.
1
2
3
4
5
6
7
8
class A {
private:
int i;
double x;
public:
char c;
void f();
};
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 281
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Composición (cont.)
La idea es que las clases de objetos se pueden usar como nuevos tipos, por
lo tanto se pueden usar en la composición de otros tipos
1
2
3
4
5
6
7
8
class B {
private:
int k;
double z;
public:
A a;
void g();
};
En este caso B::a es público, de forma que los métodos públicos de A también
se pueden llamar sobre este campo, es decir
1
2
B b;
b.a.f(); // OK
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 282
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Composición y la cadena de inicialización
Hemos visto que en el constructor de la clase podemos inicializar sus
miembros en la cadena de inicialización. En particular también se pueden
llamar constructores de los subobjetos que forman parte de la clase
1
2
3
4
5
6
7
8
9
class B {
private:
int k;
double z;
public:
B() : a(234,"jaja") { }
A a;
void g();
};
En la cadena de inicialización se pueden poner tanto constructores de
subobjetos como también inicializar objetos built-in (int, double...) por copia.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 283
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Herencia
Otra forma de elaborar clases más complejas a partir de otras más simples es
por herencia.
1
2
3
4
5
6
class C : public A {
int k;
double z;
public:
void g();
};
Se dice que C es una clase derivada de A y A es la clase base de C.
Los métodos de A se pueden llamar ahora también sobre C. en este caso
estamos diciendo C es como A pero tiene algunas cosas adicionales. Al hacer
composición estamos diciendo que C contiene a un objeto de tipo A.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 284
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Herencia (cont.)
Notar que en el caso de composición los miembros de A se acceden a través
de B::a, es decir por ejemplo
1
2
B b;
b.a.c = ’5’;
mientras que en el caso de herencia, no existe directamente el miembro B::a
de manera que los miembros de A pasan a ser directamente miembros de C
1
2
C c;
c.c = ’7’;
Al declarar en la herencia que A es público, todos los miembros y métodos de
A serán vistos a través de C con la privacidad que tenı́an en A, es decir C.c es
público y C.i es privado. Por el contrario, si declaramos
1
class C : private A { . . .
entonces todos los campos de A son privados.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 285
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Herencia (cont.)
Notar que con composición se pueden incluir en la nueva clase muchos
objetos del mismo tipo o de diferente tipo, mientras que con herencia no es
usual derivar de varias clases al mismo tiempo.
1
2
3
4
5
6
7
8
class A { . . . . };
class X { . . . . };
class B {
A a1,a2;
X x;
// . . .
};
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 286
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Redefinición de métodos
¿Qué pasa si la clase derivada tiene un método con el mismo nombre que la
clase base? Con composición no hay problema
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class A {
public:
void f();
};
class B {
public:
A a;
void f();
};
B b;
b.f(); // llama la f de B
b.a.f(); // llama la f de A
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 287
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Redefinición de métodos (cont.)
Con herencia el nuevo método redefine u oculta el método anterior
1
2
3
4
5
6
7
8
9
10
11
12
13
class A {
public:
void f();
};
class B : public A {
public:
void f();
};
B b;
b.f(); // llama la f de B
b.A::f(); // llama la f de A
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 288
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Herencia protegida
Hay una forma de herencia que es intermedia entre público y privado, y es la
herencia protected. En este caso lo métodos de la clase son privados para el
exterior pero pueden ser usados como públicos por la base derivada.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Base {
int i;
protected:
int read() const { return i; }
void set(int ii) { i = ii; }
public:
Base(int ii = 0) : i(ii) {}
int value(int m) const { return m*i; }
};
class Derived : public Base {
int j;
public:
Derived(int jj = 0) : j(jj) {}
void change(int x) { set(x); }
};
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 289
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
18
19
20
21
int main() {
Derived d;
d.change(10);
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 290
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Upcasting
El compilador nos deja sin problema castear un puntero de la clase derivada a
la clase base, porque sabe que la clase derivada tiene todas las cosas de la
base
1
2
3
4
5
6
7
class Base { //. . .
class Derived : public Base { . . .
Derived d1, d2;
Base &b = d1;
Base *p = &d2;
Esto se llama upcasting. Sin embargo, si llamamos a un método de la clase
que está implementado en las dos, llama al de la base.
1
p->f(); // llama a Base::f()
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 291
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Polimorfismo
Nosotros queremos definir clases base que son genéricas (por ejemplo
Matrix) y plantear algoritmos/operaciones genéricos para las mismas (por
ejemplo GradConj()). Estos algoritmos toman un puntero a la clase base y
llaman operaciones genéricas sobre la misma (por ejemplo el producto matriz
vector MatVec()). Luego podemos definir clases derivadas para las matrices
de distinto tipo (llena, banda, sparse, simétrica...) La idea es que cuando el
algoritmo genérico GradConj() llama al método MatVec()), ésta llamada sea
despachada a la función correspondiente en la clase derivada.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 292
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Polimorfismo (cont.)
Para que la llamada al método sea despachada a la clase derivada debemos
declarar al método virtual en la clase base.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Base {
public:
virtual void f();
//. . .
class Derived : public Base {
public:
void f();
//. . .
}
Derived d1, d2;
Base &b = d1;
b.f(); // llama a Derived::f()
Base *p = d2;
p->f(); // llama a Derived::f()
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 293
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Ejemplo polimorfismo. Integral 1D/2D/3D
Queremos calcular la integral de funciones en segmentos ([a, b]) en 1D y
productos cartesianos ([xa , xb ] × [ya , yb ]) en 2D y 3D.
Z
xb
f (x) dx,
I1 =
xa
yb
Z
Z
xb
f (x, y) dx dy,
I2 =
ya
zb
Z
Z
xa
yb
Z
xb
I3 =
f (x, y, z) dx dy dz,
za
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
ya
xa
slide 294
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Ejemplo polimorfismo. Integral 1D/2D/3D (cont.)
Empecemos definiendo el tipo de funciones de una variable
1
2
3
4
class scalarfun1d-t {
public:
virtual double eval(double x)=0;
};
Notemos que el método eval() está declarado =0 eso quiere decir que no se
implementará, por lo tanto es una clase virtual pura es decir que no se
pueden definir instancias de esta clase. Sólo es un prototipo del cual
podremos derivar clases concretas que podrán ser integradas.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 295
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Ejemplo polimorfismo. Integral 1D/2D/3D (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// LIBRARY CODE
class scalarfun1d-t {
public:
virtual double eval(double x)=0;
};
class integral1d-t {
public:
void set(int N, double a,double b,scalarfun1d-t *fxp);
double integral();
};
// USER CODE
class sin-fun-t : public scalarfun1d-t {
public:
double eval(double x) { return sin(x); }
} sin-fun;
int main() {
integral1d-t int1d;
int1d.set(100,0,1,&sin-fun);
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 296
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
22
23
24
25
}
cout << "Integral of sin(x) in [0,1] is "
<< int1d.integral() << endl;
return 0
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 297
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Clase que calcula integral 1D
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class integral1d-t {
private:
int N;
// Nbr of integration pts
double xa,xb;
// integration interval
scalarfun1d-t *fp; // ptr to function
public:
// Ctor, set values
integral1d-t(int Na=0,double xaa=NAN,
double xba=NAN,scalarfun1d-t *fpa=NULL) {
set(Na,xaa,xba,fpa);
}
// Set values
void set(int Na,double xaa,double xba,scalarfun1d-t *fpa) {
N=Na; xa=xaa; xb=xba; fp=fpa;
}
// Computes the integral using Simpson’s rule
double integral() {
double
h = (xb-xa)/N,
h2 = h/2.0,
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 298
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
21
22
23
24
25
26
27
28
29
30
31
32
33
}
};
finteg=0.0;
for (int j=0; j<N; j++) {
double x = j*h;
double f = fp->eval(x);
finteg += 2.0*f;
finteg += 4.0*fp->eval(x+h2);
}
finteg -= fp->eval(xa);
finteg += fp->eval(xb);
finteg *= h/6.0;
return finteg;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 299
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Integral 2D. Versión cruda
La integral doble la hacemos como composición de dos integrales simples
Z
yb
Z
xb
f (x, y) dx
I2 =
xa
ya
yb
Z
=
y
g(y) dy,
yb
fy (x) dx.
y
ya
ya
Z xb
g(y) =
dy,
xa
fx (y) ≡ f (x, y).
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
g(y)
xa
xb x
slide 300
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Integral 2D. Versión cruda (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class fy-t : public scalarfun1d-t {
public:
scalarfun2d-t *f2dp; // Ptr to 2var funct fx,y)
double y;
double eval(double x) { return f2dp->eval(x,y); }
} fy;
class g-t : public scalarfun1d-t {
public:
integral1d-t int1dx; // integral over x
double eval(double y) { // wrapper pass to calling class
fy.y = y;
return int1dx.integral();
}
} g;
class integral2d-t {
private:
int N;
// Nbr of integr segments
double xa,xb,ya,yb; // rectangle corners
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 301
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
integral1d-t int1dy; // integral over y
public:
void set(int Na=0,double xaa=NAN,double xba=NAN,
double yaa=NAN,double yba=NAN,
scalarfun2d-t *f2dpa=NULL) {
N = Na; xa=xaa; xb=xba; ya=yaa; yb=yba;
fy.f2dp = f2dpa;
int1dy.set(N,ya,yb,&g);
g.int1dx.set(N,xa,xb,&fy);
}
integral2d-t(int Na=0, // Ctor
double xaa=NAN,double xba=NAN,
double yaa=NAN,double yba=NAN,
scalarfun2d-t *f2dpa=NULL) {
set(Na,xaa,xba,yaa,yba,f2dpa);
}
double integral() {
// 2D integral. Integrates over y the
// integral over x
return int1dy.integral();
}
};
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 302
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// User code starts here---// Specific 2var function to be integrated
class fun-t : public scalarfun2d-t {
public:
double eval(double x,double y) {
// Must give (2/pi)ˆ2 = 0.40528
return sin(0.5*M-PI*x)*sin(0.5*M-PI*y);
}
} fun;
int main() {
int N=10;
// 2D integration example
integral2d-t int2d(N,0.0,1.0,0.0,1.0,&fun);
cout << "integral(x,y) = " << int2d.integral() << endl;
return 0;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 303
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Integral 2D. Versión cruda (cont.)
• fy y g son wrappers.
• fy toma una scalarfun2d_t y devuelve una scalarfun1d_t fijando y a un
•
•
•
•
•
valor (almacenado en el wrapper).
g es una scalarfun1d_t. Usa un objeto de la clase integradora 1D llamado
int1dx. La función eval correspondiente consiste en fijar el valor de y para
la fy y llamar a la clase integradora sobre y.
Ambos objetos pertenecen a clases fy_t y g_t.
En esta implementación hemos hecho estas clases globales y totalmente
públicas para simplificar.
La clase integradora 2D utiliza otr integrador 1D (int1dy) para integrar
sobre y.
Las dos instancias de integral1d_t son utilizadas en forma recursiva,
int1dy.eval() utiliza internamente a int1dx.eval() al evaluar la función g().
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 304
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Integral 2D. Versión cruda (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <cmath>
#include <iostream>
#include <vector>
using namespace std;
// One variable function ’f(x)’
class scalarfun1d-t {
public:
virtual double eval(double x)=0;
};
// Two variables function ’f(x,y)’
class scalarfun2d-t {
public:
virtual double eval(double x,double y)=0;
};
// Two variables function ’f(x,y,z)’
class scalarfun3d-t {
public:
virtual double eval(double x,double y,double z)=0;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 305
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
};
// Integral of a one var funct over an interval
class integral1d-t {
private:
int N;
// Nbr of integration pts
double xa,xb;
// integration interval
scalarfun1d-t *fp; // ptr to function
public:
// Ctor, set values
integral1d-t(int Na=0,double xaa=NAN,
double xba=NAN,scalarfun1d-t *fpa=NULL) {
set(Na,xaa,xba,fpa);
}
// Set values
void set(int Na,double xaa,double xba,scalarfun1d-t *fpa) {
N=Na; xa=xaa; xb=xba; fp=fpa;
}
// Computes the integral using Simpson’s rule
double integral() {
double
h = (xb-xa)/N,
h2 = h/2.0,
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 306
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
}
};
finteg=0.0;
for (int j=0; j<N; j++) {
double x = j*h;
double f = fp->eval(x);
finteg += 2.0*f;
finteg += 4.0*fp->eval(x+h2);
}
finteg -= fp->eval(xa);
finteg += fp->eval(xb);
finteg *= h/6.0;
return finteg;
// Integral of 2var functions over a rectangle
class integral2d-t {
private:
scalarfun2d-t *f2dp; // Ptr to 2var funct
integral1d-t int1dy, int1dx; // integrals over x and y
// For a given y gives the function fy(x) = f(x,y)
class fy-t : public scalarfun1d-t {
double y;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 307
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
integral2d-t *i2dp; // ptr to calling class
friend class integral2d-t;
public:
double eval(double x) { return i2dp->f2dp->eval(x,y); }
} fy;
// For a given y, integral over x: g(y) = int-{x=xa}ˆxb f(x,y) dx
class g-t : public scalarfun1d-t {
integral2d-t *i2dp; // ptr to calling class
friend class integral2d-t;
public:
double eval(double y) { // wrapper pass to calling class
return i2dp->geval(y);
}
} g;
double geval(double y) {
// Integrates over x for y=cnst
fy.y = y;
return int1dx.integral();
}
int N;
// Nbr of integr segments
double xa,xb,ya,yb; // rectangle corners
friend class fy-t;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 308
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
friend class g-t;
public:
void set(int Na=0,double xaa=NAN,double xba=NAN,
double yaa=NAN,double yba=NAN,
scalarfun2d-t *f2dpa=NULL) {
N = Na; xa=xaa; xb=xba; ya=yaa; yb=yba;
f2dp = f2dpa;
int1dy.set(N,ya,yb,&g);
int1dx.set(N,xa,xb,&fy);
}
integral2d-t(int Na=0, // Ctor
double xaa=NAN,double xba=NAN,
double yaa=NAN,double yba=NAN,
scalarfun2d-t *f2dpa=NULL) {
set(Na,xaa,xba,yaa,yba,f2dpa);
g.i2dp = this;
fy.i2dp = this;
}
double integral() {
// 2D integral. Integrates over y the
// integral over x
return int1dy.integral();
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 309
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
};
// Integral of 3var functions over a cube
class integral3d-t {
private:
scalarfun3d-t *f3dp; // Ptr to 3var funct
integral2d-t int2dxy; // integral over x,y
integral1d-t int1dz; // integral over z
// For a given z gives the function fz(x,y) = f(x,y,z)
class fz-t : public scalarfun2d-t {
double z;
integral3d-t *i3dp; // ptr to calling class
friend class integral3d-t;
public:
double eval(double x,double y) {
return i3dp->f3dp->eval(x,y,z);
}
} fz;
// For a given z, gives g(z) = integral over x,y:
// g(z) = int-{x=xa}ˆxb int-{y=ya}ˆyb f(x,y,z) dx dy
class g-t : public scalarfun1d-t {
integral3d-t *i3dp; // ptr to calling class
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 310
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
friend class integral3d-t;
public:
double eval(double z) { // wrapper pass to calling class
return i3dp->geval(z);
}
} g;
double geval(double z) {
// Integrates over x,y for z=cnst
fz.z = z;
return int2dxy.integral();
}
int N;
// Nbr of integr segments
double xa,xb,ya,yb,za,zb; // rectangle corners
friend class fz-t;
friend class g-t;
public:
void set(int Na,double xaa,double xba, // Set from args
double yaa,double yba,
double zaa,double zba,
scalarfun3d-t *f3dpa) {
N = Na; xa=xaa; xb=xba; ya=yaa; yb=yba; za=zaa; zb=zba;
f3dp = f3dpa;
int2dxy.set(N,xa,xb,ya,yb,&fz);
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 311
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
int1dz.set(N,za,zb,&g);
}
integral3d-t(int Na=0, // Ctor
double xaa=NAN,double xba=NAN,
double yaa=NAN,double yba=NAN,
double zaa=NAN,double zba=NAN,
scalarfun3d-t *f3dpa=NULL) {
set(Na,xaa,xba,yaa,yba,zaa,zba,f3dpa);
g.i3dp = this;
fz.i3dp = this;
}
double integral() { // Comp 3D integral. Integrates over z
return int1dz.integral();
}
};
// User code starts here---// Specific 1var function to be integrated
class fun-t : public scalarfun1d-t {
public:
double eval(double x) {
// Must give (2/pi) = 0.63662
return sin(0.5*M-PI*x);
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 312
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
}
} fun;
// Specific 2var function to be integrated
class fun2-t : public scalarfun2d-t {
public:
double eval(double x,double y) {
// Must give (2/pi)ˆ2 = 0.40528
return sin(0.5*M-PI*x)*sin(0.5*M-PI*y);
}
} fun2;
// Specific 3var function to be integrated
class fun3-t : public scalarfun3d-t {
public:
double eval(double x,double y,double z) {
// Must give (2/pi)ˆ3 = 0.25801
return sin(0.5*M-PI*x)
*sin(0.5*M-PI*y)*sin(0.5*M-PI*z);
}
} fun3;
int main() {
int N=10;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 313
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
208
209
210
211
212
213
214
215
216
217
218
219
220
221
}
// 1D integration example
integral1d-t int1d(N,0,1.0,&fun);
cout << "integral(x) = " << int1d.integral() << endl;
// 2D integration example
integral2d-t int2d(N,0.0,1.0,0.0,1.0,&fun2);
cout << "integral(x,y) = " << int2d.integral() << endl;
// 3D integration example
integral3d-t int3d(N,0.0,1.0,0.0,1.0,0.0,1.0,&fun3);
cout << "integral(x,y,z) = " << int3d.integral() << endl;
return 0;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 314
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Integral 2D. Versión mejorada
Funciona pero tiene algunas desprolijidades, usa variables globales y las
clases auxiliares es mejor si se anidan en la clase que la utiliza integral2d_t.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class integral2d-t {
private:
scalarfun2d-t *f2dp; // Ptr to 2var funct
integral1d-t int1dy, int1dx; // integrals over x and y
// For a given y gives the function fy(x) = f(x,y)
class fy-t : public scalarfun1d-t {
double y;
integral2d-t *i2dp; // ptr to calling class
friend class integral2d-t;
public:
double eval(double x) { return i2dp->f2dp->eval(x,y); }
} fy;
// For a given y, integral over x: g(y) = int-{x=xa}ˆxb f(x,y) dx
class g-t : public scalarfun1d-t {
integral2d-t *i2dp; // ptr to calling class
friend class integral2d-t;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 315
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public:
double eval(double y) { // wrapper pass to calling class
return i2dp->geval(y);
}
} g;
double geval(double y) {
// Integrates over x for y=cnst
fy.y = y;
return int1dx.integral();
}
int N;
// Nbr of integr segments
double xa,xb,ya,yb; // rectangle corners
friend class fy-t;
friend class g-t;
public:
void set(int Na=0,double xaa=NAN,double xba=NAN,
double yaa=NAN,double yba=NAN,
scalarfun2d-t *f2dpa=NULL) {
N = Na; xa=xaa; xb=xba; ya=yaa; yb=yba;
f2dp = f2dpa;
int1dy.set(N,ya,yb,&g);
int1dx.set(N,xa,xb,&fy);
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 316
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
40
41
42
43
44
45
46
47
48
49
50
51
52
53
integral2d-t(int Na=0, // Ctor
double xaa=NAN,double xba=NAN,
double yaa=NAN,double yba=NAN,
scalarfun2d-t *f2dpa=NULL) {
set(Na,xaa,xba,yaa,yba,f2dpa);
g.i2dp = this;
fy.i2dp = this;
}
double integral() {
// 2D integral. Integrates over y the
// integral over x
return int1dy.integral();
}
};
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 317
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Integral 3D
De la misma forma se puede hacer la integral en 3D combinando una integral
en 1D con otra en 2D.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class integral3d-t {
private:
scalarfun3d-t *f3dp; // Ptr to 3var funct
integral2d-t int2dxy; // integral over x,y
integral1d-t int1dz; // integral over z
// For a given z gives the function fz(x,y) = f(x,y,z)
class fz-t : public scalarfun2d-t {
double z;
integral3d-t *i3dp; // ptr to calling class
friend class integral3d-t;
public:
double eval(double x,double y) {
return i3dp->f3dp->eval(x,y,z);
}
} fz;
// For a given z, gives g(z) = integral over x,y:
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 318
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// g(z) = int-{x=xa}ˆxb int-{y=ya}ˆyb f(x,y,z) dx dy
class g-t : public scalarfun1d-t {
integral3d-t *i3dp; // ptr to calling class
friend class integral3d-t;
public:
double eval(double z) { // wrapper pass to calling class
return i3dp->geval(z);
}
} g;
double geval(double z) {
// Integrates over x,y for z=cnst
fz.z = z;
return int2dxy.integral();
}
int N;
// Nbr of integr segments
double xa,xb,ya,yb,za,zb; // rectangle corners
friend class fz-t;
friend class g-t;
public:
void set(int Na,double xaa,double xba, // Set from args
double yaa,double yba,
double zaa,double zba,
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 319
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
scalarfun3d-t *f3dpa) {
N = Na; xa=xaa; xb=xba; ya=yaa; yb=yba; za=zaa; zb=zba;
f3dp = f3dpa;
int2dxy.set(N,xa,xb,ya,yb,&fz);
int1dz.set(N,za,zb,&g);
}
integral3d-t(int Na=0, // Ctor
double xaa=NAN,double xba=NAN,
double yaa=NAN,double yba=NAN,
double zaa=NAN,double zba=NAN,
scalarfun3d-t *f3dpa=NULL) {
set(Na,xaa,xba,yaa,yba,zaa,zba,f3dpa);
g.i3dp = this;
fz.i3dp = this;
}
double integral() { // Comp 3D integral. Integrates over z
return int1dz.integral();
}
};
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 320
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Integral 1D/2D/3D. User code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class fun-t : public scalarfun1d-t {
public:
double eval(double x) {
// Must give (2/pi) = 0.63662
return sin(0.5*M-PI*x);
}
} fun;
// Specific 2var function to be integrated
class fun2-t : public scalarfun2d-t {
public:
double eval(double x,double y) {
// Must give (2/pi)ˆ2 = 0.40528
return sin(0.5*M-PI*x)*sin(0.5*M-PI*y);
}
} fun2;
// Specific 3var function to be integrated
class fun3-t : public scalarfun3d-t {
public:
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 321
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
double eval(double x,double y,double z) {
// Must give (2/pi)ˆ3 = 0.25801
return sin(0.5*M-PI*x)
*sin(0.5*M-PI*y)*sin(0.5*M-PI*z);
}
} fun3;
int main() {
int N=10;
// 1D integration example
integral1d-t int1d(N,0,1.0,&fun);
cout << "integral(x) = " << int1d.integral() << endl;
// 2D integration example
integral2d-t int2d(N,0.0,1.0,0.0,1.0,&fun2);
cout << "integral(x,y) = " << int2d.integral() << endl;
// 3D integration example
integral3d-t int3d(N,0.0,1.0,0.0,1.0,0.0,1.0,&fun3);
cout << "integral(x,y,z) = " << int3d.integral() << endl;
return 0;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 322
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Polimorfismo: ej. suma de los elementos de un vector
Decargar vecsum.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <cmath>
#include <iostream>
#include <vector>
using namespace std;
class vector-t {
public:
virtual int size()=0;
virtual double operator[ ](int j)=0;
};
double vecsum(vector-t &v) {
int N = v.size();
double sum = 0.0;
for (int j=0; j<N; j++) sum += v[j];
return sum;
}
// A stride, linearly spaced values
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 323
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class stride-t : public vector-t {
private:
int N;
double start, inc;
public:
stride-t(int Na, double s,double i) :
N(Na), start(s), inc(i) { }
int size() { return N; }
double operator[ ](int j) { return start+j*inc; }
};
// A wrapper to a vector<double>
class vecwrap-t : public vector-t {
private:
const vector<double> *ap;
public:
vecwrap-t(const vector<double> &a) : ap(&a) { }
int size() { return ap->size(); }
double operator[ ](int j) { return (*ap)[j]; }
};
// A plain function that computes its values
class fun-t : public vector-t {
public:
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 324
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
int N;
double p;
fun-t() : N(10), p(3.0) { }
int size() { return N; }
double operator[ ](int j) { return pow(j,p); }
};
int main() {
stride-t stride(10,0,1);
cout << "sum(0. .9): " << vecsum(stride) << endl;
vector<double> a;
double p=3; int N=10;
a.resize(N);
for (int j=0; j<N; j++) a[j] = pow(j,p);
vecwrap-t vw(a);
cout << "sum-{j=0}ˆ{j=9} xˆ3 (with vecwrap): "
<< vecsum(vw) << endl;
fun-t f;
cout << "sum-{j=0}ˆ{j=9} xˆ3 (with fun-t): "
<< vecsum(f) << endl;
return 0;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 325
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Contenedores de la
librerı́a STL
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 326
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
La clase vector
• Inicialmente eran una serie de headers con clases desarrollado por
•
•
•
•
•
Hewlett Packard.
Es una librerı́a de contenedores (vectores, listas, conjuntos, maps...) y
algoritmos (ordenamiento, filtrado, operaciones de conjuntos, eliminar
elementos duplicados...)
Están templatizados es decir cada contenedor puede obtener objetos de
un tipo arbitrario (todos del mismo), por ejemplo vector<int>,
vector<double>.
También puede contener objetos de clases definidas por el usuario
vector<A>, a condición de que la clase A cumpla con ciertas restricciones
(por ejemplo tener un constructor por defecto, operador de asignación
a1=a2...)
Muchos pueden anidarse, por ejemplo vector<vector<int>>.
Algunos pueden involucrar más de un tipo, por ejemplo map<int,string>.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 327
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
La clase vector
• Emula el comportamiento de un vector estándar de C, pero se puede
redimensionar dinámicamente y libera sus recursos dinámicamente.
vector<int> v; // declara el vector
2 v.resize(N); // lo dimensiona a N elementos
3
// OJO preserva elementos existentes.
4 vector<int> v(N); // Lo crea con N elementos
5 int z; vector<int> v(N,z); // Lo crea con N elementos =z
6 v.clear(); // Elimina todos los elementos dejando al vector vacı́o
• Tiene sobrecargado el operator[] para acceder para lectura/escritura los
elementos del vector. El acceso es en tiempo O(1).
1
x = v[j]; v[k]=z;
• v.push_back(z) inserta el elemento z al final (muy eficiente, O(1)
1
•
•
1
2
amortizado).
z = v.front(), z = v.back() accede al primer y último elemento del vector
(eficiente, O(1).
Se puede acceder a los elementos a través de iterators
// Comienzo del vector (v[0])
vector<int>::iterator q= v.begin();
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 328
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
3
4
•
•
1
2
3
4
•
1
2
3
4
5
6
7
int z = *q;
q++;
// Se dereferencian como ptrs
// Incrementa al siguiente elemento
*q equivale a v[0]. Después de hacer el incremento equivale a v[1].
La clase iterator es una clase anidada dentro de vector. Casi todos los
contenedores tienen su propia clase iterator.
El iterator v.end() es un iterator pasado el último elemento del vector
vector<int> v(10);
vector<int>::iterator q = v.end();
// ERROR: q is not dereferenciable
cout << "Last element is " << *q << endl;
q apunta a v[10] (el último elemento es v[9]).
Se puede iterar sobre todo el vector ası́
// Suma todos los elementos de v
double sum = 0;
vector<int>::iterator q = v.begin();
while (q!=v.end()) {
sum += *q;
q++;
}
• Notar que q++ se puede hacer ya que el operator++ está sobrecargado para
la clase iterator. Igual que para enteros existe la versión prefija y postfija.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 329
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
• Para vector también se puede iterar como con un vector común
1
double sum = 0;
2
for (int j=0; j<v.size(); j++) sum += v[j];
•
•
1
2
3
•
1
Pero esto se puede usar sólo con vector, con iteradores se puede iterar
sobre casi cualquiera de los otros contenedores.
Los iterators de vector<> soportan aritmética de punteros. Esto es sólo
válido para los iterators de vector, no para list<> o map<> por ejemplo.
Se puede insertar un elemento en cualquier posición del vector, sin
embargo esto puede ser costoso (O(n)).
vector<double> v(100,0);
q = v.begin() + 50; // Apunta al elemento v[50]
v.insert(q,33); // Inserta un 33 en la posición 50
Después de esto el vector tiene 101 elementos. Por supuesto esto implica
no solo redimensionar el vector sino también copiar los elementos en
[50,99] a [51,100].
Para pasar los vectores como argumentos conviene hacerlo a través de
referencias para evitar la copia. Para indicar que la función no modifica al
vector se debe declarar el argumento como const.
double vecsum(const vector<double> &w)
• Pero entonces se debe iterar sobre el mismo con un const_iterator
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 330
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
1
2
3
4
5
6
double vecsum(const vector<double> &w) {
double sum = 0.0;
vector<double>::const-iterator q = w.begin();
while (q!=w.end()) sum += *q++
return sum;
}
• Como es declarado un const_iterator no se le puede asignar un valor
1
vector<double>::const-iterator q;
2
//. . . .
3
*q = z; // error!
• Como muchos otros contenedores de las STL, permite hacer un swap con
otro contenedor
1
2
3
vector<double> v,w;
// Llena v y w . . .
v.swap(w);
Equivale a
1
2
3
4
5
vector<double> v,w, tmp;
// Llena v y w . . .
tmp = v;
v = w;
w = tmp;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 331
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
•
1
2
3
Pero sin hacer copias ni duplicados, o sea es muy eficiente.
También se puede borrar elementos o un rango de elementos
w.erase(q); // Elimina el elemento en q (ineficiente)
w.erase(p,q); // Elimina todo el rango [p,q) (ineficiente)
w.pop-back(); // Elimina el ultimo elemento (eficiente)
• En toda la documentación (y en general en ciencias de la computación) se
•
•
1
2
utilizan rangos cerrado/abierto [p,q) que quiere decir todos los elementos
desde p a q incluyendo a p pero sin incluir a q.
vector<> como casi todos los otros contenedores soportan asignación:
operator= (deep copy), operator==, (comparación por igualdad y distinto).
Para usarlo
#include <vector>
using namespace std;
• Como casi todos los otros contenedores tiene bool v.isempty() (retorna
verdadero si el contenedor está vacı́o).
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 332
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Algoritmos in-place
• Cuando se escriben códigos que manipulan contenedores muy grandes
•
•
1
2
3
4
5
6
7
8
9
10
11
12
(en tamaño de memoria requerida) es importante saber cuanta memoria
adicional se requiere para realizar la operación.
Si el contenedor es de longitud n y la cantidad de memoria requerida es
O(1) es decir no crece con el tamaño del contenedor se dice que el
algoritmo es in-place.
Por ejemplo si queremos intercambiar los contenidos de dos vectores x e
y podemos utilizar las siguientes opciones
// VERSION 1 (in-place)
for (int j=0; j<N; j++){
double aux=x[j];
x[j]=y[j];
y[j]=aux;
}
// VERSION 2 (NOT in-place)
vd-t aux=x;
x=y; y=aux;
// VERSION 3: Uses C++ vector<> builtin swap
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 333
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
x.swap(y);
15 // VERSION 4: Uses generic STL swap
16 #include <algorithm>
17 swap(x,y);
• La versión 1 es in-place, ya que si bien requiere de memoria adicional (el
13
14
•
•
•
int j y double aux), son 12 bytes y no crece con el tamaño del vector N.
En cambio para la versión 2, SI requiere de el vector aux que es de tamaño
N, por lo tanto NO es in-place.
La versión 3, utiliza el swap() builtin de la clase vector<> y SI es in-place de
acuerdo a lo que dice la documentación. Da lo mismo hacer x.swap(y) o
y.swap(x).
La versión 4 utiliza el algoritmo genérico de las STL que funciona para
casi cualquier contenedor pero que no está optimizado, por lo tanto
puede ser que en la práctica sea equivalente a la versión 1.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 334
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
La clase list
• El contenedor lista (list<>) es (como vector<>) un contenedor lineal es
decir los elementos en la lista se pueden asociar con una posición entera.
Sin embargo no se puede acceder a la posición m de la lista en forma
eficiente (es decir O(1)) ya que los elementos están almacenados en
celdas enlazadas.
1
2
3
4
list<double> L;
// pone elementos en L. . .
double z = L[m]; // NO, [ ] sólo para vectores
double z;
• Sólo se puede acceder al elemento m-ésimo haciendo un lazo.
1
double z;
2
list<double>::iterator q = L.begin();
3
for (int j=0; j<m; j++) q++;
4
z = *q; // Accede al elemento m
• La lista es doblemente enlazada es decir que se puede avanzar en las dos
direcciones (q++ y q--) eficientemente (O(1)).
• Existe otra clase slist<> que es simplemente enlazada, por lo tanto q++ es
O(1), mientras que q-- es O(n) (debe ir al principio y recorrer la lista
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 335
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
•
1
2
3
4
5
hasta encontrar la celda que apunta a q).
El interés de list<> es que permite insertar en cualquier posición muy
eficientemente (O(1))
list<double> L;
// Pone elementos en L. . .
// q apunta a cualquier posición en L
q = L.insert(q,w); // Inserta un nuevo elemento en
// el medio de la lista
• insert retorna la posición “refrescada” q.
1
L.insert(q,w); // deja q invalido
2
z = *q; // posible error en tiempo de ejecución
3
4
q = L.insert(q,w); // OK refrezca q
5
z = *q; // OK!
• Para borrar un elemento q = L.erase(q);, también se debe refrescar el
iterator.
1
2
•
1
list<int>::iterator q = L.begin();
while (q!=L.end()) q = L.erase(q);
Equivale a L.clear(), elimina todos los elementos de a uno por el frente.
También se puede pasar todo un rango de una lista a otra
list<int> L1,L2;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 336
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
2
3
•
1
2
3
4
5
•
•
// Pone elementos en L1, y L2
L1.splice(r,L2,p,q));
inserta todo el rango [p,q) de L2 en la posición r de L1. MUY EFICIENTE
(O(1)).
list<> también tiene swap. De hecho swap se puede implementar para list
en términos de splice
list<int> L1,L2,tmp;
// Pone elementos en L1, y L2
tmp.splice(tmp.begin(),L1.begin(),L1.end());
L1.splice(L1.begin(),L2.begin(),L2.end());
L2.splice(L2.begin(),tmp.begin(),tmp.end());
Toda la operación es O(1), por lo tanto es tan eficiente como swap. Pero
splice() es más general (es como swap pero para pedazos de lista).
vector no tiene splice().
Los headers son #include <list> y <slist>
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 337
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
La clase set
• Los conjuntos son contenedores que almacenan elementos diferentes
entre sı́.
1
2
3
set<int> S;
for (int j=0; j<10; j++) S.insert(j);
S.insert(5); // No hace nada (5 ya estaba)
• El método find(x) retorna la posición donde se encuentra un elemento
dado x, si el elemento no está retorna S.end()
1
2
3
4
set<int>::iterator q = S.find(x);
if (q!=S.end()) {
// x está en S y *q==x
}
• find() es muy eficiente (O(log n)). Esta es la condición de diseño de set.
• Si se declara un set<A> entonces la clase A tiene que tener los requisitos
de antes (ctor por defecto, operador de asignación). Pero además debe
tener sobrecargado el operator<. Esto es ası́ ya que el find() es eficiente
porque guarda los elementos ordenados.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 338
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
• Se puede recorrer los elementos con un iterador, están ordenados por
operator<
1
2
3
set<int>::iterator q = S.begin();
while (q!=S.end()) cout << *q++ << " ";
cout << endl;
Imprime todos los elementos ordenados por operator<
• El header correspondiente es <set>
• Notar que insert() no toma un iterator (como en list vector). En set no se
inserta en una posición en particular, ya que el mismo contenedor
mantiene los elementos en un cierto orden.
• Hay dos sabores de erase
1
S.erase(q); // Erase de un iterator (debe ser dereferenciable)
2
int z = S.erase(x); // erase de un elemento
El primero toma un iterator que debe ser dereferenciable, elimina el
elemento correspondiente y no retorna nada. El segundo toma un
elemento x y se fija si está o no en el conjunto. Si está lo elimina del
conjunto y si no, no hace nada. En ambos casos el valor de retorno es el
número de elementos efectivamente eliminados, es decir 1 o 0.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 339
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
• Operaciones binarias de conjuntos: C = A ∩ B
1 set intersection(a.begin(),a.end(),b.begin(),b.end(),
2
inserter(c,c.begin()));
• Se pueden utilizar las funciones que realizan las operaciones binarias.
Están en el header <algorithm>. No son métodos de la clase, son
funciones friend.
• C =A∪B
1 C.clear();
2 set union(A.begin(),A.end(),B.begin(),B.end(),
3
inserter(C,C.begin()));
• C =A−B
1 set difference(a.begin(),a.end(),b.begin(),b.end(),
2
inserter(c,c.begin()));
• Notar que en principio opera sobre un rango en A y otro en B e inserta la
unión de los mismos (sin elementos duplicados) en C. De la forma en que
está llamada arriba hace la operación estándar de unión.
• C =A−B
1 C.clear();
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 340
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
2
3
set-difference(A.begin(),A.end(),B.begin(),B.end(),
inserter(C,C.begin()));
• C =A∩B
1 C.clear();
2 set intersection(A.begin(),A.end(),B.begin(),B.end(),
3
inserter(C,C.begin()));
• Las operaciones binarias son muy eficientes O(n log n).
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 341
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
La clase map
• Representa una correspondencia entre claves de un conjunto dominio y
•
1
2
3
4
5
6
7
8
9
10
un conjunto imagen o contradominio. Como si fuera una base de datos
almacena pares (clave,valor) ordenados por la clave y después se puede
buscar las asignaciones por la clave.
Ejemplo, sueldos de los empleados
map<int,double> sueldos;
sueldos[13234567] = 23000.34;
sueldos[30245654] = 18356.34;
....
int dni = 34567234;
if (sueldos.find(dni)==sueldos.end()) {
// Este empleado no tiene asignado un sueldo en la tabla. . .
} else {
cout << "el sueldo correspondiente es " << sueldos[dni] << endl;
}
• El nombre utilizado para los tipos es key_t para el dominio, range_t. En el
•
1
ejemplo anterior key_t es int y range_t es double.
Cuando se itera sobre el map con el lazo tı́pico
map<int,double>::iterator q = sueldos.begin();
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 342
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
2
3
4
5
while (q!=sueldos.end()) {
cout << "DNI " << q->first << ", sueldo " << q->second << endl;
q++;
}
• Notar que los iteradores iteran sobre los pares clave, valor, de hecho son
•
•
1
2
3
estruturas de tipo pair<int,double>.
El contenedor pair es el más básico de las STL y permite agrupar dos
elementos de tipo diferente o igual: pair<int,int> dos ints,
pair<int,string>....
Los campos de pair se acceden por los miembros first y second.
pair<int,double> p;
p.first = 23;
p.second = 234.56;
• También se puede declarar pair<int,double> p(23,45.67);
• El map tiene un efecto colateral no común que es que si indexamos por
una clave que no tiene asignado un valor entonces crea una asginación
poniendo como imagen el constructor por defecto de range_t
1
2
map<int,string> M;
string z = M[5]; // Asigna z= string vacio !!!
• El tipo key_t tiene los mismos requerimientos que para un set es decir:
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 343
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
constructor por defecto y por copia, operador de asignación, operator<.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 344
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Algoritmos
• Permiten operar sobre los diferentes contenedores. Muchas veces en
•
1
2
3
4
•
•
•
•
•
1
forma transparente, el mismo algoritmo se puede aplicar a diferentes
contenedores.
Tal vez el más paradigmático y util es sort
vector<double> v;
// Pone elementos en v. . .
// Ordena por valor absoluto
sort(v.begin(),v.end());
sort(p,q) ordena los elementos en el rango [p,q). Notar que no se le pasa
el contenedor, solo dos iteradores.
Si hay que ordenar todo el contenedor hay que pasar v.begin(), v.end()
Se puede utilizar también para listas
Para conjuntos no tiene sentido, ya están internamente ordenados.
Para clases (vector<A>) ordena por operator< por lo tanto debe estar
sobrecargado.
Si se quiere ordenar por otro criterio y no se puede modificar el operator<
se puede pasar una función de comparación:
// Funcion de comparacion por valor absoluto
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 345
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
bool comp(int x,int y) { return abs(x)<abs(y); }
3
vector<int> v;
4
// Pone elementos en v. . .
5
sort(v.begin(),v.end(),comp);
• Es MUY rápido, O(n log n).
2
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 346
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Programación funcional
• Podemos escribir algoritmos que modifican los valores de un vector (u
otro contenedor), por ejemplo sumarle a todos los valores contenidos en
un árbol un valor, o duplicarlos.
1
2
3
4
5
6
7
void vecsum(vector<int> &v,int w) {
for (int j=0; j<w.size(); j++) v[j] += w;
}
void vecscale(vector<int> &v,int w) {
for (int j=0; j<w.size(); j++) v[j] *= w;
}
• Todos estos son casos particulares de un algoritmo más general
apply(v,f) que tiene como argumentos un vector v y una “función
escalar” T f(T) (donde T es el tipo del vector). y le aplica a cada uno de
los valores nodales la función en cuestión. Este es un ejemplo de
“programación funcional”, es decir, programación en los cuales los datos
de los algoritmos pueden ser también funciones.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 347
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Programación funcional (cont.)
• C++ tiene soporte para la programación funcional pasando “punteros a
•
funciones”. También se puede usar “functors”, clases que sobrecargan el
operador ().
Lenguajes funcionales puros: Lisp/Scheme, ML, Haskell... las funciones
son “objetos de primera clase”.
Solución funcional:
•
1 void apply(vector<int>&v,int (*f)(int)) {
2
int N = v.size();
3
for (int j=0; j<N; j++) v[j] = f(v[j]);
4 }
5
6 int sum10(int x) { return x+10; }
7
8 int scale10(int x) { return x*10; }
9
10 int main() {
11
int N=10;
12
vector<int> v(N);
13
for (int j=0; j<N; j++) v[j] = j;
14
dump(v,"v antes");
15
apply(v,sum10);
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 348
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
16
17
18
19
20
}
dump(v,"v += 10");
apply(v,scale10);
dump(v,"v *= 10");
return 0;
Da lo siguiente:
1
2
3
4
5
[mstorti@galileo sources]$$ ./functional.bin
v antes: 0 1 2 3 4 5 6 7 8 9
v += 10: 10 11 12 13 14 15 16 17 18 19
v *= 10: 100 110 120 130 140 150 160 170 180 190
[mstorti@galileo sources]$$
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 349
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Programación funcional (cont.)
• Se pasa el puntero a la función.
• La “signatura” es int f(int). La declaración de punteros a tales
funciones se hace reemplazando en la signatura el nombre de la función
por (*) es decir int (*)(int).
• Dentro de esta función auxiliar el puntero a función f se aplica como una
función normal.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 350
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Programación funcional (cont.)
Solución funcional con clases y polimorfismo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class map-t {
public:
virtual int f(int)=0;
};
void apply(vector<int>&v,map-t &m) {
int N = v.size();
for (int j=0; j<N; j++) v[j] = m.f(v[j]);
}
class sum-t : public map-t {
public:
int w;
int f(int x) { return x+w; }
} sum;
class scale-t : public map-t {
public:
int w;
int f(int x) { return x*w; }
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 351
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
} scale;
int main() {
int N=10;
vector<int> v(N);
for (int j=0; j<N; j++) v[j] = j;
dump(v,"v antes");
sum.w = 10;
apply(v,sum);
dump(v,"v += 10");
sum.w = 30;
apply(v,sum);
dump(v,"v += 30");
scale.w = 10;
apply(v,scale);
dump(v,"v *= 10");
scale.w = 2;
apply(v,scale);
dump(v,"v *= 2");
return 0;
}
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 352
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Da lo siguiente:
1
2
3
4
5
6
7
[mstorti@galileo sources]$ ./functional2.bin
v antes: 0 1 2 3 4 5 6 7 8 9
v += 10: 10 11 12 13 14 15 16 17 18 19
v += 30: 40 41 42 43 44 45 46 47 48 49
v *= 10: 400 410 420 430 440 450 460 470 480 490
v *= 2: 800 820 840 860 880 900 920 940 960 980
[mstorti@galileo sources]$
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 353
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Otro ejemplo de progr. fun. Reducción
• reduce(v,g,null) que toma como argumentos un vector v y una función
asociativa int g(int,int) (por ejemplo la suma, el producto, el máximo o
el mı́nimo) y devuelve el resultado de aplicar la función asociativa a todos
los valores nodales, hasta llegar a un único valor.
• null es el valor nulo para esa función asociativa, es decir g(x,null)=x para
cualquier x.
1
2
3
4
5
6
. Para g=+ es null=0, ya que es siempre x+0=0
. Para g=* es null=1, ya que es siempre x*1=x
. Para g=max es null=-Inf, ya que es siempre max(x,-Inf)=x
. Para g=min es null=+Inf, ya que es siempre min(x,+Inf)=x
. Para g=|| es null=false, ya que es siempre x||false=x
. Para g=&& es null=true, ya que es siempre x||true=x
typedef int (*assoc-t)(int,int);
int reduce(vector<int> &v,assoc-t assoc,int null) {
int z = null;
int N = v.size();
for (int j=0; j<N; j++) z = assoc(z,v[j]);
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 354
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
return z;
}
int sum(int x,int y) { return x+y; }
int max(int x,int y) { return (x>y? x : y); }
int min(int x,int y) { return (x>y? y : x); }
int main() {
int N=10;
vector<int> v(N),vcpy;
for (int j=0; j<N; j++) v[j] = j;
vcpy = v;
dump(v,"v antes");
cout << "sum(v): " << reduce(v,sum,0) << endl;
cout << "max(v): " << reduce(v,max,0) << endl;
cout << "min(v): " << reduce(v,min,0) << endl;
return 0;
}
Da:
1
2
3
4
[mstorti@galileo sources]$ ./reduce.bin
v antes: 0 1 2 3 4 5 6 7 8 9
sum(v): 45
max(v): 9
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 355
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
5
6
min(v): 0
[mstorti@galileo sources]$
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 356
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Prog funcional. Filtros
• Otra aplicación pueden ser “filtros”, como la función filter_odd, elimina
los elementos impares.
• Podrı́amos escribir una función remove_if(v,pred) que tiene como
argumentos un vector v y una función predicado bool pred(T). La función
remove_if elimina todos los elementos x para cuyos valores la función
pred(*n) retorna verdadero. La función filter_odd se podrı́a obtener
entonces simplemente pasando a remove_if una función predicado que
retorna verdadero si el argumento es impar.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 357
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Versión funcional
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void filter-odd(vector<int> &v) {
vector<int> tmp;
int N=v.size();
for (int j=0; j<N; j++)
if (v[j]%2==0) tmp.push-back(v[j]);
v = tmp;
}
typedef bool (*pred-t)(int);
void filter(vector<int> &v,pred-t p) {
vector<int> tmp;
int N=v.size();
for (int j=0; j<N; j++) if (p(v[j])) tmp.push-back(v[j]);
v = tmp;
}
bool even(int x) { return x%2==0; }
bool positive(int x) { return x>0; }
int main() {
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 358
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
}
int N=10;
vector<int> v(N),vcpy;
for (int j=0; j<N; j++) v[j] = j;
vcpy = v;
dump(v,"v antes");
filter-odd(v);
dump(v,"even(v)");
v.resize(N);
for (int j=0; j<N; j++) v[j] = j-N/2;
dump(v,"v antes");
filter(v,positive);
dump(v,"positive(v) ");
return 0;
Da:
1
2
3
4
5
6
[mstorti@galileo sources]$ ./filter.bin
v antes: 0 1 2 3 4 5 6 7 8 9
even(v): 0 2 4 6 8
v antes: -5 -4 -3 -2 -1 0 1 2 3 4
positive(v) : 1 2 3 4
[mstorti@galileo sources]$
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 359
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
Versión funcional con clases
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class pred-t {
public:
virtual bool f(int)=0;
};
void remove-if(vector<int>&v,pred-t &p) {
vector<int> tmp;
int N = v.size();
for (int j=0; j<N; j++) if(p.f(v[j])) tmp.push-back(v[j]);
v = tmp;
}
class even-t : public pred-t {
public:
bool f(int x) { return x%2==0; }
} even;
class positive-t : public pred-t {
public:
bool f(int x) { return x>0; }
} positive;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 360
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
int main() {
int N=10;
vector<int> v(N),vcpy;
for (int j=0; j<N; j++) v[j] = j-N/2;
vcpy = v;
dump(v,"v antes");
remove-if(v,even);
dump(v,"even(v)");
v = vcpy;
dump(v,"v antes");
remove-if(v,positive);
dump(v,"positive(v) ");
return 0;
}
Da:
1
2
3
4
5
6
[mstorti@galileo sources]$ ./filter2.bin
v antes: -5 -4 -3 -2 -1 0 1 2 3 4
even(v): -4 -2 0 2 4
v antes: -5 -4 -3 -2 -1 0 1 2 3 4
positive(v) : 1 2 3 4
[mstorti@galileo sources]$
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 361
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
GTP. POO Polimorfismo
1. GEOSHAPE_T Queremos escribir una serie de utilidades para permitir realizar
cálculos sobre diferentes geometrı́as 2D. (El concepto es fácilmente
extendible a 3D). Para ello nos basaremos en la siguiente
1
2
3
4
5
6
7
class geoshape-t {
public:
// Bounding box
virtual void bbox(vector<double> &bb)=0;
// Is x inside shape?
virtual bool inside(const vector<double> &x)=0;
};
• double inside(vector<double> &x); debe retornar true/false si el punto
•
x está adentro/afuera del cuerpo. En una versión más avanzada deberı́a
retornar la mı́nima distancia al perı́metro del dominio, pero por en una
primera versión podemos utilizar sólo el saber si está adentro o no.
bbox() debe retornar por bb la bounding box de la geometrı́a, es decir
un vector de longitud 4 conteniendo las coordenadas de las esquinas
inferior izquierda y superior derecha bb=[xmin ymin xmax ymax]. Esto va
a permitir definir la región sobre la cual hacer el barrido para calcular
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 362
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
integrales como el área, etc...
Escribir funciones:
1
2
3
4
•
double area(geoshape-t &gshape,int N=100);
void grav-center(geoshape-t &gshape,
vector<double> &cg,int N=100);
double inertia(geoshape-t &gshape,int N=100);
Estas funciones calculan el área, centro de gravedad y momento de
inercia (con respecto al origen) de la forma gs. Para eso hace un
cálculo de la siguiente forma (por ejemplo para el área) usando una
grilla de +N*N+ puntos cubriendo el bounding box.
1
2
3
4
5
6
7
8
double area=0.0;
for (int i=0; i<N; i++) {
x[0] = . . .;
for (int j=0; j<N; j++) {
x[1] = . . .;
if (gs.inside(x)) area += hx*hy;
}
}
•
Donde hx,hy son los pasos de la malla en ambas direcciones.
Instanciar la clase geoshape_t para cuadrados, cı́rculos, elipses,
triángulos, polı́gonos... Por ejemplo
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 363
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class square-t : public geoshape-t {
private:
double xc,yc,L;
public:
double dist(const vector<double> &x) {
return (abs(x[0]-xc)<L/2.0
&& abs(x[1]-yc)<L/2.0);
}
void bbox(vector<double> &bb) {
bb[0] = xc-L/2.0;
bb[1] = yc-L/2.0;
bb[2] = xc+L/2.0;
bb[3] = yc+L/2.0;
}
};
• Las clases deben incluir constructores apropiados, por ejemplo
•
•
1
2
square_t(xc,yc,L), circle_t(xc,yc,R).
Probar las clases verificando sus areas, CG, inercia, etc...
Escribir una clases que permite hacer operaciones booleanas
(conjuntos) de estas formas:
class intersection-t : public geoshape-t {
public:
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 364
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
3
4
5
6
}
vector<geoshape-t*> shapes;
void bbox(vector<double> &bb);
double dist(vector<double> &x);
•
•
1
2
3
Para esto:
. La bbox de la intersectión es la intersección de las bbox de sus
componentes. Es decir el XMIN de la bbox es el máximo de los xmin y
ası́ siguiendo
∗ XMIN = max(xmin)
∗ YMIN = max(ymin)
∗ XMAX = min(xmin)
∗ YMAX = min(ymin)
. Para inside(): Para que un punto está en la intersección tiene que
estar en todos las formas componentes.
Similarmente escirbir union_t.
Similarmente escribir difference_t, pero este no debe tener un vector
(ya que la operación no es asociativa).
class difference-t : public geoshape-t {
public:
geoshape-t *A,*B;
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 365
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
4
5
6
}
void bbox(vector<double> &bb);
double dist(vector<double> &x);
Debe tener dos formas A y B y el resultado debe ser la forma C=A-B. Para
la bbox usar la de A. Probar con un cuadrado con un agujero circular.
• Probar a agrupar objetos y hacer operaciones de conjuntos.
• Hacer otra clase que desplaza, rota, y escalea una forma. En general
puede ser una transformación afı́n general z=M*xx0+, donde M es la
matriz de transformación y x0 es el desplazamiento.
2. VECTOR_T. Escribir una clase polimórfica para representar vectores.
1
2
3
4
5
1
2
3
4
class vector-t {
public:
virtual int size()=0;
virtual double operator[ ](int)=0;
};
• Escribir funciones que realizan operaciones sobre el tipo
int non-null(vector-t &); // cuenta elementos no nulos
double sum(vector-t &); // suma los elementos
double max(vector-t &);
double min(vector-t &);
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 366
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
• Escribir una implementación para vectores llenos (un wrapper para
vector<>).
class fullvec-t : public vector-t {
private:
vector<double> w;
}
1
2
3
4
• Escribir una implementación stride_t para strides o sea
•
•
1
2
3
4
v[j]=startj*inc+, guarda internamente start,inc,size.
Escribir una implementación sparse_t para vectores ralos. Guarda sólo
los elementos no nulos en un vector<int> indx y vector<double> vals.
Por ejemplo si tenemos el vector
[0 0 1.2 0 3.4 0 0] entonces lo que se almacena es indx=[2 4] y
vals=[1.2 3.4]
Escribir una función double reduce(vector_t &v,assoc_t &g); que hace
una operacion de reducción sobre los elementos del vector, por
ejemplo la suma, el maximo, minimo, etc... La operación asociativa se
pasa a través de una clase assoc_t cuya expresión virtual pura es
class assoc-t {
virtual double g(double x,double y)=0;
virtual double null()=0;
};
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 367
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
null es el elemento nulo para la operación, es decir aquel tal que
x=g(x,null) para todo x. Por ejemplo 0 para la suma 1 para el producto.
class sum-t : public assoc-t {
double g(double x,double y) { return x+y; }
double null() { return 0; }
};
1
2
3
4
Para max y min deben usarse null=-INFINITY y null=INFINITY+
respectivamente.
3. Juego de 3 en lı́nea (tic-tac-toe)
• El tablero es un vector<char> board(9);
• Los casilleros están numerados por fila.
1
012
2
345
3
678
• Un valor en 0 quiere decir casillero vacio,
• Vamos a llamar a los jugadores X y O (cruces y cı́rculos). X es el que
•
•
juega primero.
Un valor negativo corresponde X un valor positivo corresponde O
Los valores (en valor absoluto) indican el orden de la jugada, e.g. un
board ası́ [3,0,0,-2,-3,-1,2,0,1] quiere decir que el tablero final es el
de abajo. El número al lado de la marca es el orden en el que se realizó
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 368
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
la jugada. O sea X1 es la primera jugada de X
1
O2|. |.
2
-------3
X2|X3|X1
4
-------5
O3|. |O1
• Los jugadores van a ser instanciaciones de la siguiente clase virtual
pura:
1
2
3
4
class t3g-player-t {
public:
virtual int move(board-t &b,int me)=0;
};
•
•
b es el tablero actual, me (puede ser -1/1) es quien soy yo (como
jugador, es decir si X o O). move debe retornar el siguiente casillero que
elige el jugador.
Escribir una función int playt3g(t3g_player_t &X,t3g_player_t &O);.
Que hace jugar a X y O. Retorna el jugador que gana o bien 0 si hay
empate.
Básicamente playt3g() debe:
. inicializar un board y llamar alternadamente a X y O.
. Chequear que la movida de cada jugador es válida.
. Registrar la movida en el tablero
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 369
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
. Chequear si el partido terminó.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
• El algoritmo serı́a ası́
board-t b;
// Initialize board b
int me = -1;
while (1) {
int you = -me;
// reference to the actual player object
t3g-player-t &player = (me==-1? O : X);
int cell;
cell = player.move(b,me);
// check cell is free. . . else bad move: wins YOU, break
// register move in board. . .
// check if me wins: wins ME, break
// Change player and continue
me = -me;
}
• Probablemente sea bueno escribir funciones como
. int game_over(board_t &b); chequea si se termino la partida, retorna
•
el resultado: -1/0/1 ganó un jugador o empate. 2 si no ganó nadie.
. void print_board(board &b); Imprime el board por pantalla.
Escribir los siguientes jugadores.
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 370
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
. random_t: retorna un casillero vacı́o al azar
. best_cell_t: Si está libre el centro lo juega, si no una de las esquinas
vacı́a al azar, sino un casillero restante vacı́o al azar.
. winner_t: Busca si gana marcando alguna casilla, si no juega una al
azar (con las prioridades de best_cell_t).
. opposer_t: Busca si gana marcando alguna casilla, si no busca si
YOU puede ganar, en ese caso le marca la casilla ganadora, si no
marca una al azar (siguiendo las prioridades de best_cell_t).
. best_player_t: Igual que opposer_t, pero en vez de marcar una según
las prioridades, releva para cada casilla a cuantas filas, columnas y
diagonales propias (es decir sin casilleros marcados por YOU) está
conectada la celda. De aquellas juega la que tiene el máximo conteo
de filas propias. Por ejemplo si el board esta ası́
1
X|.|O
2
----3
.|O|.
4
----5
.|X|.
Entonces al jugar X hace el relavamiento y le da [* 0 * 1 * 0 2 * 1].
Los * corresponden a los casilleros ocupados y los dı́gitos al conteo
de filas propias. Por lo tanto el casillero más conveniente es la
esquina inferior izquierda (casillero 6) y el board queda ası́
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 371
Programación en C++ para Ciencia e Ingenierı́a, por M.Storti, L. Dalcı́n, Rodrigo Paz
1
2
3
4
5
X|.|O
----.|O|.
----X|X|.
• Calcular las probabilidades de que cada par de jugadores gane, pierda
o empaten. Notar que la probabilidad de que uno de los jugadores
gane depende de quien empieza, por ejemplo la probabilidad de que
best_cell_t le gane a random_t no es la misma si el que empieza es
best_cell_t o random_t. Notar que se pueden hacer jugar a dos
jugadores del mismo tipo (por ejemplo dos random_t).
Facultad de Ingenierı́a y Ciencias Hı́dricas FICH - UNL
((version texstuff-1.2.9-30-gdced8b6) (date Thu Jun 4 13:04:55 2015 -0300)
(processed-date Thu Jun 4 13:05:35 2015 -0300))
slide 372
Descargar