Академический Документы
Профессиональный Документы
Культура Документы
http://www.cimec.org.ar/prog
Facultad de Ingeniera y Ciencias Hdricas
Universidad Nacional del Litoral http://www.unl.edu.ar
de Metodos
Centro de Investigacion
Computacionales - CIMEC
INTEC, (CONICET-UNL), http://www.cimec.org.ar
slide 1
Autores
Mario Storti <mario.storti@gmail.>
Lisandro Dalcn, <dalcinl@gmail.com>
Rodrigo Paz, <rodrigo.r.paz@gmail.com>
slide 2
Contents
. slide 12.....Compilacion
slide 3
.
.
.
.
.
slide 40.....Strings de C
slide 41.....Strings de C++
slide 43.....Escribir y leer de archivos
slide 45.....La clase vector
slide 48.....Ejercicios
slide 49.....El C en C++
. slide 50.....Funciones
. slide 51.....Valores de retorno
slide 4
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
slide 79.....Especificadores
slide 82.....Punteros
slide 92.....Referencias
slide 95.....Punteros a void
slide 97.....Scope de las variables
slide 99.....Definiendo variables on-the-fly
slide 103.....Variables locales
slide 107.....Punteros a variables locales
slide 5
.
.
.
.
.
.
slide 125.....Enums
slide 128.....Arreglos de estructuras
slide 129.....Punteros y arreglos
slide 131.....Arreglos de punteros
slide 135.....Aritmetica
de punteros
slide 137.....Tamanos
de estructuras
Orientada a Objetos
slide 138.....Programacion
de datos
. slide 139.....Abstraccion
slide 6
.
.
.
.
.
.
.
.
.
.
.
.
.
.
slide 196.....Eliminacion
slide 198.....Clase stash con ctor/dtor
slide 202.....Stack con ctor/dtor
de agregados
slide 205.....Initializacion
de estructuras
slide 206.....Inicializacion
slide 207.....Sobrecarga de funciones
slide 211.....Argumentos por default
slide 212.....Constantes
slide 215.....Punteros a arreglos constantes de caracteres
slide 216.....Const en argumentos de funciones
slide 217.....Const en clases
slide 218.....Objetos const y funciones de la clase
slide 220.....Chapter 5
. slide 221.....Funciones inline
. slide 225.....Especificaciones de linkedicion
. slide 227.....Referencias en C++
. slide 233.....Reglas para las referencias
. slide 235.....Paso por referencia y por copia
. slide 236.....El constructor por copia
slide 7
slide 272.....Chapter
. slide 273.....Otros operadores que se pueden sobrecargar
dinamica
. slide 274.....Creacion
de objetos
en C++
. slide 276.....Uso de la memoria dinamica
. slide 278.....Porque usar new y no arreglos
. slide 279.....Memory exhaust
. slide 280.....Composicion
y la cadena de inicializacion
. slide 282.....Composicion
. slide 283.....Herencia
de metodos
. slide 286.....Redefinicion
. slide 288.....Herencia protegida
. slide 290.....Upcasting
. slide 291.....Polimorfismo
. slide 293.....Ejemplo polimorfismo. Integral 1D/2D/3D
. slide 297.....Clase que calcula integral 1D
cruda
. slide 299.....Integral 2D. Version
mejorada
. slide 314.....Integral 2D. Version
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL
((version texstuff-1.2.5-48-gc81615e) (date Wed Jan 21 14:11:47 2015 -0300)
(processed-date Wed Jan 21 14:12:00 2015 -0300))
slide 8
.
.
.
.
slide 317.....Integral 3D
slide 320.....Integral 1D/2D/3D. User code
slide 322.....Polimorfismo: ej. suma de los elementos de un vector
slide ??.....Ejemplo clase vector sparse
slide 325.....Contenedores de la librera STL
. slide 327.....La librera STL
. slide 327.....La clase vector
. slide 332.....La clase list
. slide 335.....La clase set
. slide 339.....La clase map
. slide 341.....Algoritmos
slide 9
Dictado
Docentes de la catedra:
. Mario Storti <mario.storti@gmail.>
. Lisandro Dalcn, <dalcinl@gmail.com>
. Rodrigo Paz, <rodrigo.r.paz@gmail.com>
slide 10
Elementos basicos
de
programacion
slide 11
vs. interpretes
Compilacion
tienen un interprete,
genera codigo
de maquina,
el cual es ejecutado directamente por el
procesador.
el codigo
rapido,
Ventajas de la compilacion:
suele ser mas
y mas
compacto.
facil
interprete.
Tambien
es mas
debuggear.
C++ es un lenguaje compilado.
slide 12
El proceso de compilacion
simple es cuando todo el codigo
El caso mas
del programa esta en un
archivo fuente:
solo
conviene hacer
1
2
3
slide 13
(cont.)
El proceso de compilacion
hace
Si solo se modifica uno de los archivos (prog1.cpp), entonces solo
falta recompilar ese.
librera
libpetsc.a, libmkl.a.
slide 14
El preprocesador CPP
int v[100000];
if (n<100000) {
....
}
Se puede simplificar de la siguiente forma
1
2
3
4
5
slide 15
especfico del lenguaje C/C++, incluso puede usarse (y se usa) para otros
lenguajes como Fortran.
usuales son
Las directivas mas
slide 16
(/usr/bin/cpp).
slide 17
Chequeo de tipos
typed language),
C++ es un lenguaje tipado (aka tipeo estatico,
en ingles
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
on. Esto es bueno porque
permite detectar tempranamente errores. (Es equivalente al chequeo de
unidades en Fsica).
slide 18
por separado
Compilacion
En C++ se favorece que un programa grande se pueda dividir en
pequenas.
fracciones mas
El mecanismo fundamental para dividir un
pequenas
slide 19
en el codigo
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
en prog2.cpp antes de
correctos. Para eso hay que declarar a la funcion
poder llamarla
1
2
3
4
slide 20
Declaraciones y definiciones
le dice al compilador que esa funcion
existe y su
Una declaracion
prototipo o signatura, es decir el tipo de argumentos de entrada y de
salida. Por ejemplo
int gcd(int,int);
por otra parte dice especficamente como la funcion
realiza
La definicion
su tarea
1
2
3
4
5
6
7
8
9
10
11
slide 21
// archivo prog1.cpp
int f(int x) { return 2*x; }
// archivo prog2.cpp
int f(int) { return 3*x; }
// -> ERROR: m
ultiplemente definida
slide 22
int m;
int m;
...
int m; // ERROR
slide 23
extern int m;
...
3 extern int m; // OK
4 . . .
5 int m; // OK
con las funciones, para hacer hincapie en
extern se puede usar tambien
1
2
por ejemplo
que es una declaracion,
1
slide 24
Incluyendo headers
Es usual que en nuestros programas escribamos una serie de funciones
utilizaremos en otras partes del programa.
que despues
// 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
// 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
slide 25
// utils.h
int gcd(int m,int n);
double cos(double alpha);
double sin(double alpha);
en prog1.cpp hay que solo incluir el header:
Entonces despues
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.
slide 26
1
2
3
4
5
slide 27
Usando libreras
Entonces si tengo que usar una librera matrix que esta 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 librera 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 librera basta con incluir el header
1 // myprog.cpp
2 #include <matrix.h>
3 . . .
slide 28
#include <matrix>
que es estandar
de C
. Matematicas
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++
slide 29
1
2
3
#include <iostream>
...
cout << "Hola";
El operador << en C quiere decir en realidad otra cosa: es para desplazar
los bits en un numero
slide 30
Namespaces
funciones
A medida que una librera o programa crecen cada vez hay mas
aleatorios.
Lamentablemente la libc ya usa el nombre rand() para generar un unico
numero aleatorio.
que se usaba en C era prependizar un prefijo identificador
Una solucion
de la librera a todas las funciones de la misma matrix_rand(),
matrix_sum(), matrix_prod(). Esto se vuelve muy engorroso.
slide 31
Namespaces (cont.)
C++ provee un mecanismo para evitar colisiones llamado namespaces.
Todos los archivos de la librera se incluyen en un namespace de la
siguiente forma
// matrix.cpp
2 namespace matrix {
3
void rand(. . .) { /* . . . */ }
4
double sum(. . .) { /* . . . */ }
5
void prod(. . .) { /* . . . */ }
6 }
las funciones se deben llamar con el operador de
Entonces despues
1
1
2
3
4
5
// prog.cpp
using namespace matrix;
rand(A);
double m = max(A);
slide 32
Namespaces (cont.)
en
Muchas utilidades y variables estandar
de C++, por ejemplo cout, estan
el namespace std de manera que o bien hay que hacer
1
2
3
slide 33
Estructura de un programa
de funciones y
Un programa en C/C++ esta compuesto de una coleccion
int function() {
2
// Function code here (this is a comment)
3 }
pares de llaves balanceadas ({}) adentro de la funcion
slide 34
1
2
3
slide 35
Hello world
1
2
3
4
5
6
7
8
arreglos de caracteres.
endl es un final de lnea.
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
potente. A los strings de C se los debe llamar mas
correctamente
mas
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 lnea, \t un TAB, \0 un NULL, \\ una
barra invertida.
slide 36
de arreglos de caracters
Concatenacion
Para incluir arreglos de caracteres muy largos se puede simplemente
de otro (puede ser en diferentes lneas). El CPP
poner uno a continuacion
se encarga de juntarlos todos en una sola lnea: "aaa" "bbbb" es
completamente equivalente a "aaabbbb".
1
2
3
4
5
6
7
8
9
10
11
slide 37
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
slide 38
slide 39
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;
}
slide 40
Strings de C++
Para eso C++ tiene objetos llamados strings que permiten manipularlos en
simple y con menor probabilidad de error.
forma mucho mas
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <cstring>
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;
}
slide 41
//: 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;
}
slide 42
1
2
3
4
5
6
7
8
9
10
11
slide 43
slide 44
La clase vector
Un vector es un contenedor que permite guardar un numero
indefinido de
slide 45
slide 46
slide 47
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
especfica en un archivo. Ayuda: usar == para comparar strings.
4. Escribir un programa que imprime las lneas de un archivo de texto en
orden inverso.
slide 48
El C en C++
slide 49
Funciones
Para evitar errores, C/C++ usa el concepto de prototipo o signatura de
funciones.
hay que declararla.
Antes de usar una funcion
los argumentos con que es llamada deben coincidir con
Al usar la funcion
el el tipo que fueron declarados.
slide 50
Valores de retorno
de la funcion
debe indicar el valor de retorno. Si la funcion
La declaracion
no retorna nada usar void:
slide 51
// 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;
} ///:
slide 52
funcion
En caso que la librera no este documentada hay que directamente ver los
slide 53
1
2
3
4
5
6
A==B. Esta
como por ejemplo el resultado del operador de comparacion
retorna directamente un valor logico
expresion
true o false. No confundiir
A=B.
con el operador de asignacion
if (n) { . . . }
if (n!=0) { . . . . }
slide 54
if (!(n==0)) { . . . . } // ! is negation
slide 55
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
slide 56
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 << "Its greater than 5" << endl;
else
if(i < 5)
cout << "Its less than 5 " << endl;
else
cout << "Its 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;
slide 57
If-else (cont.)
por eso no hace falta
Notar que todo el if actua
como una sola instruccion,
encerrarlo con un {}.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if(i > 5)
cout << "Its greater than 5" << endl;
else
if(i < 5)
cout << "Its less than 5 " << endl;
else
cout << "Its equal to 5 " << endl;
// es equivalente a
if(i > 5) { cout << "Its greater than 5" << endl; }
else {
if(i < 5)
cout << "Its less than 5 " << endl;
else
cout << "Its equal to 5 " << endl;
}
mut util
Es una convencion
indentar ambos bloques del if para mejorar la
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL
((version texstuff-1.2.5-48-gc81615e) (date Wed Jan 21 14:11:47 2015 -0300)
(processed-date Wed Jan 21 14:12:00 2015 -0300))
slide 58
legibilidad.
slide 59
while
while(expression)
statement
se evalua
Como antes statement puede ser simple o compuesto. La expresion
int x=0;
while (x<5) x=2; // ejecuta una vez el lazo
while (x<5) x=34; // ejecuta indefinidamente
x=0;
while (x<5) x++; // ejecuta el bloque 5 veces
slide 60
while (cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
slide 61
while (cont.)
dentro del condicional puede ser tan elaborada como se
En C la condicion
es que debe retornar un valor logico
quiera, la unica
restriccion
(o convertible
a logico),
incluso puede ser que el cuerpo del lazo este vaco
1
2
3
por ejemplo
1
slide 62
do-while
1
2
3
do
statement
while(expression);
condicion.
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);
slide 63
Lazo for
La forma del for es
1
2
int i=0;
while(i<n) {
// This block is executed n times
i++;
}
slide 64
slide 65
slide 66
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 << "Its an a" << endl; break;
case b: cout << "Its a b" << endl; break;
default: cout << "Neither a or b" << endl;
}
slide 67
slide 68
goto
La sentencia goto permite saltar a otro punto del programa. Se lo considera
aunque a veces
muchas veces como una mala practica
de programacion,
puede ser util,
slide 69
17
slide 70
Recursion
de un
Muchos problemas son intrnsecamente recursivos, es decir la solucion
de uno menor con el mismo algoritmo,
problema esta dada por la solucion
de factorial se puede hacer en forma recursiva
por ejemplo la definicion
n! = n (n 1)!
(1)
correcta es
> 1, la definicion
1;
si n = 1;
n! =
n (n 1)! ; si n > 1
(2)
= 1 corta la recursion.
int factorial(int n) {
if (n==1) return 1;
else return n*factorial(n-1);
}
slide 71
Recursion (cont.)
es muy elegante para resolver problemas, pero puede ser
La recursion
simple si calculamos el
demandante en terminos
de recursos. Es mas
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;
}
fac = fac*j;
de strings...
logicos,
concatenacion
slide 72
Operadores
que funciones, con una sintaxis especial. Un
Los operadores no son mas
series de valores y devuelve un resultado.
operador toma una o mas
1
a = b + c;
a = sum(b,c);
a = b * c + d;
es equivalente a
1
a = (b * c) + d;
parentesis
para forzar el orden en que se evaluan
las expresiones.
slide 73
int m,n=5;
m = n++; // n=6, m=5
int m,n=5;
m = ++n; // n=6, m=6
int next-prime(int n) {
while (!is-prime(n++)) { }
return n;
}
slide 74
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!!
slide 75
Tipos de datos
caracteres.
int un entero de al menos 16 bits (2 bytes)
float un numero
precision).
slide 76
slide 77
depender de la maquina
y del compilador, entonce los valores maximos
y
definidos en headers float.h y limits.h,
mnimos (los lmites) estan
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
slide 78
Especificadores
Para representar enteros se utiliza un bit de los 32 disponibles para
representar el signo.
se van a utilizar enteros positivos entonces podemos usar ese bit
Si solo
para extender un factor 2 el rango.
int en el rango [-2147483648,2147483647]
unsigned int en el rango [0,4294967295]
slide 79
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;
slide 80
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;
} ///:
slide 81
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
1
2
int n;
cout << "variable n is in position " << &n << endl;
[mstorti@galileo garage]$$ ./ptr.bin
variable n is in position 0x7fff1c46d92c
quisieramos
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
slide 82
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;
}
slide 83
Punteros (cont.)
El resultado es
1
2
3
4
5
6
7
8
9
10
slide 84
Punteros (cont.)
en memoria de un variable puede cambiar de una corrida a
La direccion
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;
una
El sufijo _p o simplemente p indica que es un puntero (es solo
convencion).
slide 85
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;
int *number-p,*n-p,*m-p;
de una
Podemos asignar a una variable de tipo puntero la direccion
de ese proxy
variable, lo cual nos permite modificarla a traves
1
2
3
int number=100;
int *number-p = &number;
*number-p = 25; // Ahora number contiene 25!!
slide 86
Punteros (cont.)
OJO: el hecho de declarar una variable de tipo puntero no significa que
int *p;
cout << "contenido de *p " << *p << endl; // ERROR
int x;
p = &x;
cout << "contenido de *p " << *p << endl; // OK
slide 87
Punteros (cont.)
de usos, el primero que podemos ver aca
Los punteros tienen un monton
modifique un objeto
es el de causar que una funcion
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
using namespace std;
void f(int a) {
cout << "a = " << a <<
a = 5;
cout << "a = " << a <<
}
int main() {
int x = 47;
cout << "x = " << x <<
f(x);
cout << "x = " << x <<
}
endl;
endl;
endl;
endl;
slide 88
Punteros (cont.)
Imprime:
1
2
3
4
x
a
a
x
=
=
=
=
47
47
5
47
que se
Como la variable a en f() es una copia, resulta que la modificacion
hace en f() no persiste, de manera que queda el mismo valor.
slide 89
Punteros (cont.)
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;
}
slide 90
Punteros (cont.)
Imprime:
1
2
3
4
5
6
x = 47
&x = 0065FE00
p = 0065FE00
*p = 47
p = 0065FE00
x=5
slide 91
Referencias
Los punteros son muy utiles
dereferenciacion.
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& 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;
slide 92
18
slide 93
Referencias (cont.)
Imprime:
1
2
3
4
5
6
x = 47
&x = 0065FE00
r = 47
&r = 0065FE00
r=5
x=5
slide 94
Punteros a void
acepta que asignemos a una variable de tipo int* la
El compilador solo
de una variable de tipo int, en otro caso da un error
direccion
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
slide 95
int i = 99;
void* vp = &i;
*vp = 3; // Error de compilacion
int i = 99;
void* vp = &i;
*((int*)vp) = 3; // OK!
int i = 99;
void* vp = &i;
// Compila OK, posible error en tiempo de ejecucion
*((string*)vp) = "Hello world";
slide 96
slide 97
19
20
21
22
23
24
25
slide 98
slide 99
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
while(char c = cin.get() != q) {
cout << c << " wasnt 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;
}
slide 100
// == 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() {
slide 101
19
20
globe = 47;
slide 102
Variables locales
se les
Las variables que existen dentro de un scope son locales, tambien
llama automaticas
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) {
slide 103
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;
}
slide 104
slide 105
19
20
slide 106
int *p;
for (int j=0; j<N; j++) {
int z;
p = &z;
...
}
// ERROR (z no existe mas)
cout << "contenido de *p " << *p << endl;
slide 107
Variables estaticas
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;
}
slide 108
Variables estaticas
(cont.)
El resultado es:
1
2
3
4
5
6
7
8
9
10
11
12
slide 109
Constantes
Si se utilizara muchas veces un valor que es constante se pueden hacer a
de un macro
traves
1
#define PI 3.141459
slide 110
Operadores. Asignacion
A=4;
4=A;
slide 111
Operadores matematicos
x += 5;
es equivalente a
1
x = x + 5;
slide 112
Operadores relacionales
Son
1
slide 113
Operadores logicos
Son && (and) y || (or). Recordar que en C/C++ muchos tipos se castean
automaticamente
a bool, siendo 0 el valor falso y cualquier otro valor
verdadero. Cuando se imprimen los valores booleanos dan 0 o 1. ! es la
negacion.
Son operadores cortocircuitados es decir si hacemos
1
logica
expr1 | | expr2
si la primera da verdadero.
slide 114
El operador hook
Es una forma muy compacta de escribir un if-else. Por ejemplo esta expresion
calcula el mnimo de dos valores
1
x = (m<n ? m : n);
(m<n ? m : n) = 23;
slide 115
slide 116
Operadores de cast
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!
slide 117
Operador sizeof
de una variable o tipo en bytes
Retorna el tamano
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)
-
slide 118
1
2
slide 119
Estructuras
Se pueden definir nuevos tipos agrupando varios miembros en una
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
struct A {
char c;
int m;
float a;
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);
slide 120
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;
}
}
slide 121
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
next
next
c='b' x=2
next
slide 122
Estructuras (cont.)
El resultado es
1
2
3
4
5
6
7
8
9
slide 123
Arrow operator
(*cp).x es decir
Como en el ejemplo anterior es muy comun
la compinacion
tener un puntero a una estructura cp y querer tomar un miembro x de la
slide 124
Enums
Supongamos que queremos definir una estructura shape que contiene una
forma geometrica,
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
1
2
3
4
struct shape {
double x,y;
int gtype;
};
que imprime la forma sera algo as como
Entonces una funcion
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 corresponda a cada forma.
slide 125
Enums (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
...
}
slide 126
Enums (cont.)
Pero, como ya dijimos, es preferible no usar macros, para esto esta el enum:
1
2
3
4
5
6
7
8
9
10
11
12
13
nosotros.
El compilador traduce cada identificador de la lista a un entero
consecutivo.
Se puede forzar a que tomen un valor especfico
slide 127
Arreglos de estructuras
Vimos que podemos definir arreglos como int v[100].
lo podemos hacer con estructuras cell sv[100]
Tambien
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
de la celda es de 16 bytes (8 para el doble y 8 para el
ya que el tamano
puntero):
1
2
3
slide 128
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
comienza el area
asignada al vector. Esto lo podemos verificar imprimiento la
del primer elemento
direccion
1
2
slide 129
int v[100];
int *p= &v[0];
for (int j=0; j<1000, j++) *(p+j) = 100*j;
int v[100];
int *p= &v[0];
for (int j=0; j<1000, j++) p[j] = 100*j;
slide 130
Arreglos de punteros
se pueden tener arreglos de punteros
Tambien
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
slide 131
1
2
3
4
5
6
7
8
9
10
$$
0:
1:
2:
3:
4:
5:
6:
7:
8:
El shell (en este caso bash) divide los argumentos pasados en la lnea de
comando por whitespace y construye un arreglo de strings
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL
((version texstuff-1.2.5-48-gc81615e) (date Wed Jan 21 14:11:47 2015 -0300)
(processed-date Wed Jan 21 14:12:00 2015 -0300))
slide 132
posicion
vector se puede producir un error
int v[100];
2 . . .
3 v[100] = x; // Muy probablemente SIGSEGV o SEGFAULT
del vector en tiempo de compilacion
(hay una
Se debe conocer el tamano
1
slide 133
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
slide 134
Aritmetica
de punteros
Se pueden hacer cuentas con punteros de tipo ptr = ptr + int y todas las
derivadas, por ejemplo
1
2
3
4
5
slide 135
Aritmetica
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 = " <<
produce
1
2
3
4
5
slide 136
Tamanos
de estructuras
del
Cuando se usan estructuras con tipos mezclados puede ser que el tamano
struct A {
char c;
double d;
};
da
1
2
sizeof(B) -> 24
sizeof(C) -> 16
slide 137
Orientada
Programacion
a Objetos
slide 138
de datos
Abstraccion
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
slide 139
de datos (cont.)
Abstraccion
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 Ingeniera y Ciencias Hdricas FICH - UNL
((version texstuff-1.2.5-48-gc81615e) (date Wed Jan 21 14:11:47 2015 -0300)
(processed-date Wed Jan 21 14:12:00 2015 -0300))
slide 140
de datos (cont.)
Abstraccion
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
slide 141
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
}
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;
slide 142
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
}
void cleanup(CStash* s) {
if(s->storage != 0) {
cout << "freeing storage" << endl;
delete [ ]s->storage;
}
}
slide 143
de datos (cont.)
Abstraccion
CStash es un tipo que permite almacenar una cantidad ilimitada de
size.
elementos de tamano
Tiene un area
de almacenamiento interno unsigned char *storage.
del almacenamiento
Se pueden agregar elementos con add(), si el tamano
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
de los elementos al valor entrado por el
diferentes contadores y el tamano
usuario (int sz).
todo el area
previa y agregando el nuevo elemento.
quantity es el numero
de lugares disponibles
next es la cantidad de lugares realmente ocupados.
fetch() retorna el puntero al lugar donde comienza el elemento en la
index. Primero chequea que efectivamente el ndice este en el
posicion
rango de valores apropiados (0<=index<next). En caso contrario retorna un
puntero nulo. Esta garantizado que el puntero nulo no apunta a ningun
slide 144
lado de la memoria.
count() retorna la cantidad de elementos que hay en el contenedor.
Simplemente retorna next.
dinamica
Alocacion
de memoria: Como no sabemos en principio que
va a tomar el area
tamano
de memoria vamos alocando dinamicamente
con el operador new
se hace
El area
utilizada debe ser liberada. Si no (y si la alocacion
1
delete t;
2 delete[ ] tp;
Las areas
de memoria reservadas con new se alocan en el heap. Si el heap
1
slide 145
de datos (cont.)
Abstraccion
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++)
slide 146
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
slide 147
de datos (cont.)
Abstraccion
Resultado:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
slide 148
POO basica
automatica.
del espacio de nombres: Si necesitamos otro contenedor no
Polucion
vamos a poder usar los nombres initialize() y cleanup(). Una posible
sera usar nombres con prefijos CStash_initialize(),
solucion
CStash_cleanup() ...
slide 149
POO basica
(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);
};
slide 150
POO basica
(cont.)
Ahora las funciones aparecen dentro de la estructura, de manera que esta
1
2
actua
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
Stash s1,s2,s3;
s1.initialize(10);
slide 151
POO basica
(cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
slide 152
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
}
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;
slide 153
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
}
void Stash::cleanup() {
if(storage != 0) {
cout << "freeing storage" << endl;
delete [ ]storage;
}
}
slide 154
POO basica
(cont.)
Adentro de las funciones miembro no es necesario dereferenciar al objeto
1
2
3
4
5
6
7
8
slide 155
POO basica
(cont.)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
slide 156
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();
slide 157
POO basica
(cont.)
Las llamadas a funciones de la librera se convierten as
1 CStash initialize(&s1,sz);
2 s1.initialize(size);
slide 158
Inclusion de headers
Algunos headers pueden incluir a otros, por ejemplo el header de una
librera lib1.h puede incluir iostream. Entonces si otra librera lib2.h
incluye iostream, al querer incluir a las dos libreras
tambien
#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).
codigo.
1
2
3
4
5
6
7
#define FLAG
#ifdef FLAG
//. . .
#else
//. . .
#endif
Notar que es muy diferente este condicional del preprocesador que el
uno de los bloques se
if-else de C++. En el del preprocesador solo
compila. Quiere decir que se puede usar para usar diferentes pedazos de
slide 159
codigo
que de otra forma no compilara. Por ejemplo
#ifdef HAS-PETSC
2 //. . . Version que usa la libreria PETSC
3 #else
4 //. . . Version alternativa
5 #endif
100
1000 // -> Error
100
1000 // OK!
slide 160
#include <stash.h>
2 #include <stash.h> // no es incluido esta vez!!
El macro centinela STASH_H debe ser unico
1
2
#include <libreria1/stash.h>
#include <libreria2/stash.h> // Error: este no es incluido
Deberian usar LIBRERIA1_STASH_H y LIBRERIA2_STASH_H.
slide 161
su codigo
pierde la proteccion
de nombres.
que queramos impedir con los namespace: la colision
en
Por lo tanto la regla es: NO usar using namespace.. en los headers, solo
los .cpp
slide 162
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
data
next
data
next
data
slide 163
next
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();
};
slide 164
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 Ingeniera y Ciencias Hdricas FICH - UNL
((version texstuff-1.2.5-48-gc81615e) (date Wed Jan 21 14:11:47 2015 -0300)
(processed-date Wed Jan 21 14:12:00 2015 -0300))
slide 165
void cleanup();
12 };
del tipo se define
Notar que al definir el tipo Link en la misma declaracion
11
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.
de inicializacion
slide 166
slide 167
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");
}
slide 168
slide 169
21
22
23
24
25
26
while((s = (string*)textlines.pop()) != 0) {
cout << *s << endl;
delete s;
}
textlines.cleanup();
slide 170
sobre scoping
Mas
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
slide 171
de nombres, la OOP
para organizar el codigo
y prevenir la colision
Orientada a Objetos) es mucho mas
que esto.
(Programacion
slide 172
Ocultando la implementacion
definiciones de estructuras
Una librera tpica de C consiste de una o mas
(struct) y funciones asociadas que actuan
se
implementacion.
del usuario depende de que la alocacion
dejara de funcionar.
su codigo
slide 173
(cont.)
Ocultando la implementacion
En C esto se puede resolver parcialmente si el programador especifica en la
de la librera las funciones con las cuales el usuario de la
documentacion
de las funciones provistas, y
estructura debe manipular los objetos a traves
hasta que punto puede usar directamente los datos almacenados en la
un pacto entre el usuario y el programador, el
estructura. Pero esto es solo
compilador no tiene forma de conocer estas reglas y prevenir al usuario de
manipular los objetos indebidamente.
slide 174
struct A {
int i,j;
float f;
void func();
};
struct A {
public:
int i,j;
float f;
void func();
};
slide 175
correspondientes solo
(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
slide 176
19
20
21
22
slide 177
slide 178
Amistad (Friendship)
que no es miembro de la
El keyword friend permite declarar que una funcion
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
slide 179
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;
}
slide 180
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);
}
slide 181
El estandar
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
};
slide 182
Object layout
de C++ fue que codigo
Cuando el compilador organiza los datos dentro del objeto los guarda en
en la estructura.
memoria en forma contigua, en el orden en el que estan
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
en el momento de compilacion.
Una
publicos
slide 183
Clases
Controlar el acceso a los miembros de una estructura es parte de lo que se
class A {
int i,j,k;
public:
double z;
void f();
};
struct B {
private:
int i,j,k;
slide 184
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;
};
slide 185
Clases (cont.)
Vemos la clase Stash ahora con control de acceso. Todos los datos son
inflate() tambien
ya que solo
es usada internamente.
privados. La funcion
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();
};
slide 186
Clases (cont.)
es
En Stack ahora hacemos que toda la estructura Link sea privada o sea solo
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.
declararla como clase, pero entonces deberamos
Podramos tambien
declarar friend a Stack.
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL
((version texstuff-1.2.5-48-gc81615e) (date Wed Jan 21 14:11:47 2015 -0300)
(processed-date Wed Jan 21 14:12:00 2015 -0300))
slide 187
Otra razon
innecesaria. Una solucion
es usar punteros opacos, (aka
la recompilacion
el nombre Cheshires cat). Por ejemplo
handles, en C++ se usa tambien
podramos ocultar completamente los detalles de Stash como esta abajo. El
tiene acceso a stashwrapper.h.
usuario solo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
slide 188
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
slide 189
y cleanup
Inicializacion
comunes cuando se utilizan libreras es no inicializar
Uno de los errores mas
y destruir (cleanup) apropiadamente los objetos. En las libreras que hemos
descripto hasta ahora esto se haca con funciones initialize() y cleanup().
Una de las ideas que C++ toma de la OOP es que estas operaciones de
y cleanup se hagan en forma automatica.
inicializacion
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
slide 190
y cleanup (cont.)
Inicializacion
y otra de cleanup)
Para esto debe haber dos funciones (una de inicializacion
class A {
public:
A() { /*. . .*/ }
// . . .
};
void f() {
A a; // a is created -> calls ctor A::A()
// Usar a . . .
// . . .
}
slide 191
El constructor
El ctor puede tener argumentos y puede haber varios constructores. Cual
slide 192
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
Es llamado automaticamente
cuando termina el scope del objeto.
slide 193
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;
} ///:
slide 194
El destructor (cont.)
Salida del programa:
1
2
3
4
5
6
7
slide 195
Eliminacion
Es tpico de C tener que definir todas las variables al principio de un scope
slide 196
17
18
19
20
21
22
int retval = 0;
cin >> retval;
require(retval != 0);
int y = retval + 3;
G g(y);
slide 197
slide 198
slide 199
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
}
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;
slide 200
48
49
50
51
52
53
54
55
56
57
58
59
60
61
}
Stash::Stash() {
if(storage != 0) {
cout << "freeing storage" << endl;
delete [ ]storage;
}
}
slide 201
// 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();
};
slide 202
#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;
slide 203
25
26
27
28
29
30
31
32
33
34
}
Stack::Stack() {
require(head == 0, "Stack not empty");
} ///:
slide 204
de agregados
Initializacion
Agregados son arreglos, estructuras y clases. Arreglos son de elementos
int a[5] = { 1, 2, 3, 4, 5 };
Conteo automatico:
automaticamente
dimensiona c como c[4] a partir del
numero
int c[ ] = { 1, 2, 3, 4 };
slide 205
de estructuras
Inicializacion
1
2
3
4
5
6
7
struct X {
int i;
float f;
char c;
};
X x1 = { 1, 2.2, c };
slide 206
Sobrecarga de funciones
Vimos que el compilador decora los nombres de las funciones que
void f();
class X { void f(); };
Aca los nombres de las f no colisionan ya que son en realildad ::f() y X::f().
decora los nombres de las funciones con el tipo de
El compilador tambien
sus argumentos de manera que
1
2
void print(char);
void print(float);
slide 207
interno de la funcion
1
2
3
4
5
El mangling _Z1fcd hace que el nombre del del archivo objeto sea unico.
El
lenguaje C no hace mangling, por eso no se puede sobrecargar.
slide 208
[mstorti@galileo
00000000000002d4
0000000000000000
[mstorti@galileo
slide 209
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();
};
slide 210
slide 211
Constantes
Objetos de los cuales se supone que su valor no va a variar se pueden definir
como constantes
1
2
slide 212
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;
int x = 23;
const int* u;
u = &x;
*u = 55; // ERROR!
slide 213
Constantes (cont.)
pueden ser constantes las dos cosas, el puntero y el objeto
Tambien
1
2
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
slide 214
slide 215
Recordar que pasar por puntero o referencia puede ser para modificar el valor
para evitar la copia. Incluyendo el const permite pasar los
o tambien
argumentos en forma eficiente, pero evitando que accidentalmente se
modifique el objeto.
slide 216
Const en clases
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();
};
slide 217
class A {
public:
void f() const;
void g();
};
void A::f() const { /* . . . */ }
A a;
a.f();
slide 218
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
}
slide 219
Chapter 5
slide 220
Funciones inline
hay un costo adicional de pasar
Cada vez que hay una llamada a funcion
aparece duplicado en
La desventaja es que el codigo
binario de la funcion
grande. Tambien
algun
punto se toma la direccion
Funciones definidas en la misma clase (y por lo tanto en el header
normalmente) son candidatas a ser promovidas a inline por el compilador.
slide 221
// 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; }
//. . .
};
slide 222
funcion
Para evitar esto una forma que exista en C para crear las funciones inline era
definir macros, por ejemplo
1
slide 223
a = 5+1*5+1
apropiada se obtiene protegiendo los argumentos con
La definicion
parentesis.
slide 224
Especificaciones de linkedicion
digamos
Cuando declaramos una funcion,
1
se llama a esto
dijimos que internamente el compilador la decora (tambien
entonces esta
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
Notar que
Esto le dice al compilador que no decore el nombre de esa funcion.
no puede ser sobrecargada.
por lo tanto esa funcion
slide 225
extern "C" {
#include <clibheader.h>
}
slide 226
Referencias en C++
slide 227
class A {
// . . . .
void f(); // modifica a *this
};
// arreglo multidimensional de As
A av[100][100][100];
// Un elemento particular de av
int i,j,k;
//. . .
av[i][j][k].f();
slide 228
// arreglo multidimensional de As
int v[100][100][100];
// Un elemento particular de av
int x = av[i][j][k];
// . . . hace calculos con x
// Pisa el valor en av
av[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.
slide 229
// arreglo multidimensional de As
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.
cada vez que llamamos a AIJK estamos haciendo una cuenta con
Ademas
correspondiente en v.
i,j,k para encontrar la posicion
slide 230
// arreglo multidimensional de As
A av[100][100][100];
// Un elemento particular de av
int i,j,k;
A *ap = &av[i][j][k];
ap->f();
slide 231
// arreglo multidimensional de As
A av[100][100][100];
// Un elemento particular de av
int i,j,k;
A &a = av[i][j][k];
a.f();
de la clase.
Es eficiente, limpio, y a se manipula como un objeto mas
slide 232
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
slide 233
slide 234
void f(A a, B b) {. . .}
class A {
//. . .
A(A&) { . . . } // Constructor por copia
};
slide 235
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).
con una deep copy) y
Esto se llama una shallow copy (por contraposicion
de almacenamiento dinamico
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
}
slide 236
Sobrecarga de operadores
[], (),
de los operadores usuales, matematicos
(+, -, *, /), de indexacion
(+=, -=, *=, /=), logicos
slide 237
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
slide 238
#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;
slide 239
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;
slide 240
como en Fortran).
exponenciacion,
No se puede cambiar la regla de precedencia de los operadores.
slide 241
#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:
slide 242
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) {
slide 243
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
}
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;
slide 244
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;
slide 245
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);
slide 246
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";
slide 247
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);
} ///:
slide 248
slide 249
slide 250
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
slide 251
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);
slide 252
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,
slide 253
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
slide 254
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
}
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,
slide 255
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
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;
slide 256
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) {
slide 257
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
}
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;
}
slide 258
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
slide 259
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
}
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
slide 260
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); \
slide 261
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
}
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) {}
slide 262
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
slide 263
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
}
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:
slide 264
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
}
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;
slide 265
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;
}
slide 266
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
slide 267
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
slide 268
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
slide 269
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
}
int main() {
out << "member functions:" << endl;
Byte b1(47), b2(9);
k(b1, b2);
} ///:
slide 270
Integer A;
A += A;
operator=(). A esto se le
Lo mismo pasa con el operador de asignacion
Sobre todo si hay componentes
llama chequear por autoasignacion.
apuntadas por punteros.
slide 271
Chapter
slide 272
vector por un entero. En las STL se usa en las clases vector<> y map<>
slide 273
dinamica
Creacion
de objetos
Las variables de un programa pueden ser alocados en tres formas diferentes
y normalmente viven en secciones diferentes de memoria
del mismo.
programa y viven durante toda la duracion
Objetos dinamicos
son alocados al entrar en el scope correspondiente.
se hace en el stack.
La alocacion
Objetos pueden ser alocados y desalocados en cualquier momento
(responsabilidad del programador) en el heap.
slide 274
uso basico
para objetos en C sera 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:
slide 275
automatica
por el operador. Para esto las funciones malloc() y free() (que
de todo son funciones de librera es decir que no son parte del
despues
lenguaje) son reemplazadas por operadores intrnsecos del lenguaje: new y
delete.
1
2
3
A *p = new A;
// . . . usa *p
delete p;
slide 276
A *p = new A(x,y,z);
A av[4] = {1,2,3}
slide 277
slide 278
Memory exhaust
Que ocurre si se acaba la memoria? En viejos compiladores new retornaba un
de tipo bad_alloc().
puntero nulo. En el estandar
actual lanza una excepcion
antigua se le puede usar new(std::nothrow)
Por compatibilidad con la version
que emula el primer comportamiento.
1
2
3
4
5
6
7
8
9
10
11
12
13
slide 279
Composicion
Hasta ahora vimos clases/estructuras que se construyen a partir de tipos
basicos
usando composicion.
1
2
3
4
5
6
7
8
class A {
private:
int i;
double x;
public:
char c;
void f();
};
slide 280
(cont.)
Composicion
La idea es que las clases de objetos se pueden usar como nuevos tipos, por
de otros tipos
lo tanto se pueden usar en la composicion
1
2
3
4
5
6
7
8
class B {
private:
int k;
double z;
public:
A a;
void g();
};
de A tambien
se pueden llamar sobre este campo, es decir
1
2
B b;
b.a.f(); // OK
slide 281
y la cadena de inicializacion
Composicion
Hemos visto que en el constructor de la clase podemos inicializar sus
En particular tambien
se pueden
miembros en la cadena de inicializacion.
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();
};
slide 282
Herencia
complejas a partir de otras mas
simples es
Otra forma de elaborar clases mas
por herencia.
1
2
3
4
5
6
class C : public A {
int k;
double z;
public:
void g();
};
slide 283
Herencia (cont.)
los miembros de A se acceden a traves
B b;
b.a.c = 5;
C c;
c.c = 7;
class C : private A { . . .
slide 284
Herencia (cont.)
se pueden incluir en la nueva clase muchos
Notar que con composicion
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;
// . . .
};
slide 285
de metodos
Redefinicion
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
slide 286
de metodos
Redefinicion
(cont.)
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
slide 287
Herencia protegida
Hay una forma de herencia que es intermedia entre publico
y privado, y es la
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); }
};
slide 288
18
19
20
21
int main() {
Derived d;
d.change(10);
}
slide 289
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
slide 290
Polimorfismo
algoritmo generico
GradConj() llama al metodo
MatVec()), esta
llamada sea
correspondiente en la clase derivada.
despachada a la funcion
slide 291
Polimorfismo (cont.)
declarar al metodo
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()
slide 292
xb
f (x) dx,
I1 =
xa
yb
xb
f (x, y) dx dy,
I2 =
ya
zb
xa
yb
xb
I3 =
f (x, y, z) dx dy dz,
za
ya
xa
slide 293
class scalarfun1d-t {
public:
virtual double eval(double x)=0;
};
slide 294
// 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:
double eval(double x) { return sin(x); }
} sin-fun;
int main() {
integral1d-t int1d;
int1d.set(100,0,1,&sin-fun);
slide 295
22
23
24
25
slide 296
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 Simpsons rule
double integral() {
double
h = (xb-xa)/N,
h2 = h/2.0,
slide 297
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;
slide 298
cruda
Integral 2D. Version
de dos integrales simples
La integral doble la hacemos como composicion
yb
Z
xb
f (x, y) dx
I2 =
xa
ya
yb
Z
=
g(y) dy,
yb
fy (x) dx.
y
ya
ya
Z xb
g(y) =
dy,
xa
g(y)
xa
xb x
slide 299
cruda (cont.)
Integral 2D. Version
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
slide 300
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
slide 301
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
slide 302
cruda (cont.)
Integral 2D. Version
fy y g son wrappers.
fy toma una scalarfun2d_t y devuelve una scalarfun1d_t fijando y a un
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,
g().
int1dy.eval() utiliza internamente a int1dx.eval() al evaluar la funcion
slide 303
cruda (cont.)
Integral 2D. Version
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;
slide 304
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 Simpsons rule
double integral() {
double
h = (xb-xa)/N,
h2 = h/2.0,
slide 305
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;
slide 306
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
slide 307
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
slide 308
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
slide 309
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
slide 310
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);
slide 311
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;
slide 312
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;
slide 313
mejorada
Integral 2D. Version
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;
slide 314
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);
}
slide 315
40
41
42
43
44
45
46
47
48
49
50
51
52
53
slide 316
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:
slide 317
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
slide 318
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();
}
};
slide 319
slide 320
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
slide 321
#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
class stride-t : public vector-t {
private:
int N;
slide 322
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
slide 323
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
slide 324
Contenedores de la
librera STL
slide 325
La clase vector
Inicialmente eran una serie de headers con clases desarrollado por
Hewlett Packard.
Es una librera de contenedores (vectores, listas, conjuntos, maps...) y
algoritmos (ordenamiento, filtrado, operaciones de conjuntos, eliminar
elementos duplicados...)
templatizados es decir cada contenedor puede obtener objetos de
Estan
un tipo arbitrario (todos del mismo), por ejemplo vector<int>,
vector<double>.
puede contener objetos de clases definidas por el usuario
Tambien
de que la clase A cumpla con ciertas restricciones
vector<A>, a condicion
slide 326
La clase vector
redimensionar dinamicamente
y libera sus recursos dinamicamente.
amortizado).
v.push_front(z) inserta el elemento z al comienzo del vector (muy
ineficiente, O(n)).
z = v.front(), z = v.back() accede al primer y ultimo
slide 327
1
2
3
1
2
1
2
3
4
5
6
7
vector<int> v(10);
vector<int>::iterator q = v.end();
q apunta a v[10] (el ultimo
elemento es v[9].
Se puede iterar sobre todo el vector as
Notar que q++ se puede hacer ya que el operator++ esta sobrecargado para
prefija y postfija.
la clase iterator. Igual que para enteros existe la version
se puede hacer como con un vector comun
Para vector tambien
slide 328
1
2
1
2
3
double sum = 0;
for (int j=0; j<v.size(); j++) sum += v[j];
con vector, con iteradores se puede iterar
Pero esto se puede usar solo
sobre casi cualquiera de los otros contenedores.
vector<double> v(100,0);
q = v.begin() + 50; // Apunta al elemento v[50]
v.insert(q,33); // Inserta un 33 en la posicion 50
de esto el vector tiene 101 elementos. Por supuesto esto implica
Despues
copiar los elementos en
no solo redimensionar el vector sino tambien
[50,99] a [51,100].
de
Para pasar los vectores como argumentos conviene hacerlo a traves
no modifica al
referencias para evitar la copia. Para indicar que la funcion
vector se debe declarar el argumento como const.
slide 329
1
2
3
4
5
6
vector<double> v,w;
// Llena v y w . . .
v.swap(w);
Equivale a
1
2
3
4
5
slide 330
1
2
3
4
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.
#include <vector>
using namespace std;
Como casi todos los otros contenedores tiene bool v.isempty() (retorna
verdaderi si el contenedor esta vaco).
slide 331
La clase list
El contenedor lista (list<>) es (como vector<>) un contenedor lineal es
entera.
decir los elementos en la lista se pueden asociar con una posicion
m de la lista en forma
Sin embargo no se puede acceder a la posicion
almacenados en
eficiente (es decir O(1)) ya que los elementos estan
celdas enlazadas.
1
2
3
4
list<double> L;
// pone elementos en L. . .
double z = L[m]; // NO, [ ] s
olo para vectores
double z;
Solo
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 Ingeniera y Ciencias Hdricas FICH - UNL
((version texstuff-1.2.5-48-gc81615e) (date Wed Jan 21 14:11:47 2015 -0300)
(processed-date Wed Jan 21 14:12:00 2015 -0300))
slide 332
1
2
3
4
list<double> L;
// Pone elementos en L. . .
// q apunta a cualquier posici
on en L
q = L.insert(q,w); // Inserta un nuevo elemento en el medio de la lista
refrescada q.
insert retorna la posicion
1
L.insert(q,w); // deja q invalido
2
z = *q; // posible error en tiempo de ejecucion
3
4
q = L.insert(q,w); // OK refrezca q
5
z = *q; // OK!
se debe refrescar el
Para borrar un elemento q = L.erase(q);, tambien
iterator.
1
2
1
2
list<int>::iterator q = L.begin();
while (q!=L.end()) q = L.erase(q);
list<int> L1,L2;
// Pone elementos en L1, y L2
slide 333
1
2
3
4
5
L1.splice(r,L2,p,q));
r de L1. MUY EFICIENTE
inserta todo el rango [p,q) de L2 en la posicion
(O(1)).
tiene swap. De hecho swap se puede implementar para list
list<> tambien
en terminos
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());
es O(1), por lo tanto es tan eficiente como swap. Pero
Toda la operacion
general (es como swap pero para pedazos de lista).
splice() es mas
vector no tiene splice().
Los headers son #include <list> y <slist>
slide 334
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)
1
2
3
4
set<int>::iterator q = S.find(x);
if (q!=S.end()) {
// x esta en S y *q==x
}
de diseno
de set.
find() es muy eficiente (O(log n)). Esta es la condicion
debe
de antes (ctor por defecto, operador de asignacion).
Pero ademas
tener sobrecargado el operator<. Esto es as ya que el find() es eficiente
porque guarda los elementos ordenados.
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL
((version texstuff-1.2.5-48-gc81615e) (date Wed Jan 21 14:11:47 2015 -0300)
(processed-date Wed Jan 21 14:12:00 2015 -0300))
slide 335
ordenados por
Se puede recorrer los elementos con un iterador, estan
operator<
1
2
3
set<int>::iterator q = S.begin();
while (q!=S.end()) cout << *q++ << " ";
cout << endl;
slide 336
C =AB
1 set difference(a.begin(),a.end(),b.begin(),b.end(),
2
inserter(c,c.begin()));
C =AB
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.
en el header <algorithm>. No son metodos
Estan
de la clase, son
funciones friend.
C =AB
1 C.clear();
2 set union(A.begin(),A.end(),B.begin(),B.end(),
3
inserter(C,C.begin()));
Notar que en principio opera sobre un rango en A y otro en B e inserta la
C =AB
1 C.clear();
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL
((version texstuff-1.2.5-48-gc81615e) (date Wed Jan 21 14:11:47 2015 -0300)
(processed-date Wed Jan 21 14:12:00 2015 -0300))
slide 337
2
3
set-difference(A.begin(),A.end(),B.begin(),B.end(),
inserter(C,C.begin()));
C =AB
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).
slide 338
La clase map
Representa una correspondencia entre claves de un conjunto dominio y
1
2
3
4
5
6
7
8
9
10
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;
}
map<int,double>::iterator q = sueldos.begin();
slide 339
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
pair<int,double> p;
p.first = 23;
p.second = 234.56;
una clave que no tiene asignado un valor entonces crea una asginacion
poniendo como imagen el constructor por defecto de range_t
1
2
map<int,string> M;
string z = M[5]; // Asigna z= string vacio !!!
slide 340
Algoritmos
Permiten operar sobre los diferentes contenedores. Muchas veces en
1
2
3
4
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()
para listas
Se puede utilizar tambien
internamente ordenados.
Para conjuntos no tiene sentido, ya estan
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<
de comparacion:
slide 341
Es MUY rapido,
O(n log n).
2
slide 342