Professional Documents
Culture Documents
Autores
Contents
. 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 53.....Usando la librera estandar de C
. slide 54.....Control de ejecucion. True and False
. slide 56.....If-else
. slide 60.....while
. slide 63.....do-while
. slide 64.....Lazo for
. slide 66.....Break and continue
. slide 67.....La sentencia switch
. slide 69.....goto
. slide 71.....Recursion
. slide 73.....Operadores
. slide 74.....Operadores de auto incremento
. slide 76.....Tipos de datos
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 4
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
. 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 108.....Variables estaticas
. slide 110.....Constantes
. slide 111.....Operadores. Asignacion
. slide 112.....Operadores matematicos
. slide 113.....Operadores relacionales
. slide 114.....Operadores logicos
. slide 115.....El operador hook
. slide 116.....Errores comunes con los operadores
. slide 117.....Operadores de cast
. slide 118.....Operador sizeof
. slide 119.....typedef: Aliases de tipos
. slide 120.....Estructuras
. slide 124.....Arrow operator
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 5
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
. 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
slide 138.....Programacion Orientada a Objetos
. slide 139.....Abstraccion de datos
. slide 149.....POO basica
. slide 159.....Inclusion de headers
. slide 163.....Estructuras enlazadas
. slide 171.....Mas sobre scoping
. slide 172.....Tipos Abstractos de Datos (ADT)
. slide 173.....Ocultando la implementacion
. slide 175.....Control de acceso a los miembros
. slide 179.....Amistad (Friendship)
. slide 182.....Anidamiento (nesting) y amistad
. slide 183.....Object layout
. slide 184.....Clases
. slide 188.....Ocultando totalmente la implementacion
. slide 190.....Inicializacion y cleanup
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 6
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
. 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
Dictado
Docentes de la catedra:
. Mario Storti <mario.storti@gmail.>
. Lisandro Dalcn, <dalcinl@gmail.com>
. Rodrigo Paz, <rodrigo.r.paz@gmail.com>
Elementos basicos de
programacion
El proceso de compilacion
A veces la librera puede ser que haya sido desarrollada por un tercero:
libpetsc.a, libmkl.a.
El preprocesador CPP
Muchas veces hay texto que se repite muchas veces en el codigo. En ese
caso se pueden usar macros
1 int v[100000];
if (n<100000) {
....
2
3
4 }
Se puede simplificar de la siguiente forma
1 #define MAX 100000
2 int v[MAX];
if (n<MAX) {
....
3
4
5 }
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.
2 #include <library.h>
3
4 #define CHECK(a,n) if (a>n) error()
(/usr/bin/cpp).
Chequeo de tipos
3 a = "Hello";
Declaraciones y definiciones
Por el contrario, la funcion solo puede estar definida una sola vez en todos
los archivos del programa, ya que si no el compilador no sabra cual usar.
1 // archivo prog1.cpp
2 int f(int x) { return 2*x; }
3
4 // archivo prog2.cpp
5 int f(int) { return 3*x; }
6 // -> ERROR: multiplemente definida
3 int m; // ERROR
3 extern int m; // OK
4 . . .
5 int m; // OK
extern se puede usar tambien con las funciones, para hacer hincapie en
que es una declaracion, por ejemplo
1 extern int f(int x);
pero no es necesario.
Incluyendo headers
Esto se vuelve muy engorroso si hay que incluir las declaraciones en cada
4 int x = gcd(m,n);
5 double c = cos(alpha);
double s = sin(theta);
...
6
7
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 compilacion
1 $$ g++ -I/home/mstorti/utils -c -o prog.o prog.cpp
1 // lo encuentra en /home/mstorti/utils
2 #include <utils4.h>
3 // lo encuentra en /home/mstorti/utils/src
#include <src/utils5.h>
...
4
5
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 . . .
La extension que se usa para los archivos fuente puede ser .cpp, .cxx.
Para los headers se utiliza .h, .hpp, .hxx.
Para evitar confusiones y ambiguedad con las extensiones, C++ introdujo
el concepto de include sin extension. El traductor se encarga de convertir
el nombre y buscar la extension.
1 #include <matrix>
Existe una librera con muchas funciones muy utiles que es estandar de C
y se llama justamente libc.a. Entre otras incluye funciones
. 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 #include <stdio.h> // C
2 #include <cstdio> // C++
Para imprimir por terminal hay que usar el operador << de la clase
iostream:
#include <iostream>
...
1
2
Namespaces
A medida que una librera o programa crecen cada vez hay mas funciones
y es muy posible que se produzca la colision de nombres. Por ejemplo, si
escribo una librera para manipular matrices, puedo querer implementar
una funcion rand() que llena la matriz con numeros aleatorios.
Lamentablemente la libc ya usa el nombre rand() para generar un unico
numero aleatorio.
Una solucion que se usaba en C era prependizar un prefijo identificador
de la librera a todas las funciones de la misma matrix_rand(),
matrix_sum(), matrix_prod(). Esto se vuelve muy engorroso.
Namespaces (cont.)
3 void rand(. . .) { /* . . . */ }
4 double sum(. . .) { /* . . . */ }
5 void prod(. . .) { /* . . . */ }
6 }
Namespaces (cont.)
Estructura de un programa
Hello world
1 // Saying Hello with C++
2 #include <iostream> // Stream declarations
3 using namespace std;
4
5 int main() {
6 cout << "Hello, World. I am "
7 << 8 << " Today" << endl;
8 }
Le pasamos a cout una serie de elementos de diferentes tipos: enteros,
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
mas potente. A los strings de C se los debe llamar mas 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 lnea, \t un TAB, \0 un NULL, \\ una
barra invertida.
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 36
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
5 int main() {
6 cout << "This is far too long to put on a "
7 "single line but it can be broken up with "
8 "no ill effects\nas long as there is no "
9 "punctuation separating adjacent character "
10 "arrays.\n";
11 }
Entrada de datos
5 int main() {
6 int number;
7 cout << "Enter a decimal number: ";
8 cin >> number;
9 cout << "value in octal = 0"
10 << oct << number << endl;
11 cout << "value in hex = 0x"
12 << hex << number << endl;
13 }
oct y hex son manipulators, cambian el estado de cout.
Dentro de la librera estandar de C hay una funcion 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 ejecutara en la lnea de
comandos.
1 // Call another program
2 #include <cstdlib> // Declare system()
3 using namespace std;
4
5 int main() {
6 system("date -u");
7 }
Strings de C
Strings de C++
Para eso C++ tiene objetos llamados strings que permiten manipularlos en
forma mucho mas simple y con menor probabilidad de error.
1 #include <iostream>
2 #include <cstring>
3 using namespace std;
4
5 int main() {
6 // concatenate two character arrays s1 and s2
7 string s1 = "Hola ";
8 string s2 = "mundo.";
9 string s = s1 + s2;
10 cout << s << endl;
11 return 0;
12 }
1 //: C02:HelloStrings.cpp
2 // The basics of the Standard C++ string class
3 #include <string>
4 #include <iostream>
5 using namespace std;
6
7 int main() {
8 string s1, s2; // Empty strings
9 string s3 = "Hello, World."; // Initialized
10 string s4("I am"); // Also initialized
11 s2 = "Today"; // Assigning to a string
12 s1 = s3 + " " + s4; // Combining strings
13 s1 += " 8 "; // Appending to a string
14 cout << s1 + s2 + "." << endl;
15 }
7 int main() {
8 ifstream in("FillString.cpp");
9 string s, line;
10 while(getline(in, line))
11 s += line + "\n";
12 cout << s;
13 }
Que pasa si queremos guardar cada lnea en un string separado?
La clase vector
8 int main() {
9 vector<string> v;
10 ifstream in("Fillvector.cpp");
11 string line;
12 while(getline(in, line))
13 v.push-back(line); // Add the line to the end
14 // Add line numbers:
15 for(int i = 0; i < v.size(); i++)
16 cout << i << ": " << v[i] << endl;
17 }
vector tambien puede guardar cualquier otro tipo, por ejemplo enteros:
1 // Creating a vector that holds integers
2 #include <iostream>
3 #include <vector>
4 using namespace std;
5
6 int main() {
7 vector<int> v;
8 for(int i = 0; i < 10; i++)
9 v.push-back(i);
10 for(int i = 0; i < v.size(); i++)
11 cout << v[i] << ", ";
12 cout << endl;
13 for(int i = 0; i < v.size(); i++)
14 v[i] = v[i] * 10; // Assignment
15 for(int i = 0; i < v.size(); i++)
16 cout << v[i] << ", ";
17 cout << endl;
18 }
Ejercicios
El C en C++
Funciones
En algun lugar la funcion tiene que estar definida, aqu los nombres de los
argumentos tienen que aparecer para poder ser usados en la funcion
1 int translate(float x, float y, float z) {
2 x = y = z;
3 // . . .
4 }
Valores de retorno
3 if (!(n==0)) { . . . . } // ! is negation
If-else
4 // o
5
6 if (expression)
7 statement
8 else
9 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 if (n>0) x=23; // sentencia simple
2
If-else (cont.)
1 int i;
2 cout << "type a number and Enter" << endl;
3 cin >> i;
4 if(i > 5)
5 cout << "Its greater than 5" << endl;
6 else
7 if(i < 5)
8 cout << "Its less than 5 " << endl;
9 else
10 cout << "Its equal to 5 " << endl;
11
12 cout << "type a number and Enter" << endl;
13 cin >> i;
14 if(i < 10)
15 if(i > 5) // if is just another statement
16 cout << "5 < i < 10" << endl;
17 else
18 cout << "i <= 5" << endl;
19 else // Matches if(i < 10)
20 cout << "i >= 10" << endl;
If-else (cont.)
Notar que todo el if actua como una sola instruccion, por eso no hace falta
encerrarlo con un {}.
1 if(i > 5)
2 cout << "Its greater than 5" << endl;
3 else
4 if(i < 5)
5 cout << "Its less than 5 " << endl;
6 else
7 cout << "Its equal to 5 " << endl;
8
9 // es equivalente a
10
11 if(i > 5) { cout << "Its greater than 5" << endl; }
12 else {
13 if(i < 5)
14 cout << "Its less than 5 " << endl;
15 else
16 cout << "Its equal to 5 " << endl;
17 }
Es una convencion mut util indentar ambos bloques del if para mejorar la
legibilidad.
while
while (cont.)
5 int main() {
6 int secret = 15;
7 int guess = 0;
8 // != is the not-equal conditional:
9 while(guess != secret) { // Compound statement
10 cout << "guess the number: ";
11 cin >> guess;
12 }
13 cout << "You guessed it!" << endl;
14 }
while (cont.)
3 while() { }
por ejemplo
1 while(is-prime(n)) n++; // busca el primer n no primo
do-while
1 do
2 statement
3 while(expression);
Es similar al while pero ahora statement es ejecutado antes de verificar la
condicion.
1 n=0;
2 while (n>0) /* body. . .*/ ; // body is not executed
3
4 n=0;
5 do
6 /* body. . .*/ ; // body is executed once
7 while (n>0);
Lazo for
continue es similar a break pero hace que se ejecute la siguiente iteracion del
lazo
1 for (int j=0; j<n; j++) {
2 //. . . .
3 if (!is-prime(j)) continue;
4 // do this only for primes. . .
5 }
La sentencia switch
Va comparando la variable selector hasta que coincide con uno de los case
1 switch(selector) {
2 case integral-value1 : statement; break;
3 case integral-value2 : statement; break;
4 case integral-value3 : statement; break;
5 case integral-value4 : statement; break;
6 case integral-value5 : statement; break;
7 (. . .)
8 default: statement;
9 }
por ejemplo
1 char c;
2 //. . .
3 switch (c) {
4 case a: cout << "Its an a" << endl; break;
5 case b: cout << "Its a b" << endl; break;
6 default: cout << "Neither a or b" << endl;
7 }
goto
17 }
Recursion
Muchos problemas son intrnsecamente recursivos, es decir la solucion de un
problema esta dada por la solucion de uno menor con el mismo algoritmo,
por ejemplo la definicion de factorial se puede hacer en forma recursiva
n! = n (n 1)! (1)
Recursion (cont.)
Operadores
Los operadores no son mas que funciones, con una sintaxis especial. Un
operador toma una o mas 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 cuestion importante con los operadores es la precedencia de los
mismos. Para los operadores matematicos 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
parentesis para forzar el orden en que se evaluan las expresiones.
4 int m,n=5;
5 m = ++n; // n=6, m=6
Por ejemplo la siguiente funcion retorna el primer primo siguiente (mayor o
igual) a n.
1 int next-prime(int n) {
2 while (!is-prime(n++)) { }
3 return n;
4 }
Tipos de datos
4 int main() {
5 // Definition without initialization:
6 char protein;
7 int carbohydrates;
8 float fiber;
9 double fat;
10 // Simultaneous definition & initialization:
11 char pizza = A, pop = Z;
12 int dongdings = 100, twinkles = 150,
13 heehos = 200;
14 float chocolate = 3.14159;
15 // Exponential notation:
16 double fudge-ripple = 6e-4;
17 }
Como los tipos basicos tienen una cantidad de bits fija pueden representar un
tamano maximo. Por ejemplo los enteros de 16 bits solo pueden estar entre
-32768 y +32768. Ademas el tamano del tipo (la cantidad de bits) puede
depender de la maquina y del compilador, entonce los valores maximos y
mnimos (los lmites) estan definidos en headers float.h y limits.h,
1 #include <climits>
2
Especificadores
Especificadores (cont.)
1 //: C03:Specify.cpp
2 // Demonstrates the use of specifiers
3 #include <iostream>
4 using namespace std;
5
6 int main() {
7 char c;
8 unsigned char cu;
9 int i;
10 unsigned int iu;
11 short int is;
12 short iis; // Same as short int
13 unsigned short int isu;
14 unsigned short iisu;
15 long int il;
16 long iil; // Same as long int
17 unsigned long int ilu;
18 unsigned long iilu;
19 float f;
20 double d;
21 long double ld;
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 80
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
22 cout
23 << "\n char= " << sizeof(c)
24 << "\n unsigned char = " << sizeof(cu)
25 << "\n int = " << sizeof(i)
26 << "\n unsigned int = " << sizeof(iu)
27 << "\n short = " << sizeof(is)
28 << "\n unsigned short = " << sizeof(isu)
29 << "\n long = " << sizeof(il)
30 << "\n unsigned long = " << sizeof(ilu)
31 << "\n float = " << sizeof(f)
32 << "\n double = " << sizeof(d)
33 << "\n long double = " << sizeof(ld)
34 << endl;
35 } ///:
Punteros
Punteros (cont.)
1 #include <iostream>
2 using namespace std;
3
Punteros (cont.)
El resultado es
1 [mstorti@galileo garage]$$ ./pointers.bin
2 f(): 4196630
3 dog: 6295956
4 cat: 6295960
5 bird: 6295964
6 fish: 6295968
7 i: 140736631158572
8 j: 140736631158568
9 k: 140736631158564
10 [mstorti@galileo garage]$$
Punteros (cont.)
Punteros (cont.)
Punteros (cont.)
Punteros (cont.)
Los punteros tienen un monton de usos, el primero que podemos ver aca
es el de causar que una funcion modifique un objeto
1 #include <iostream>
2 using namespace std;
3
4 void f(int a) {
5 cout << "a = " << a << endl;
6 a = 5;
7 cout << "a = " << a << endl;
8 }
9
10 int main() {
11 int x = 47;
12 cout << "x = " << x << endl;
13 f(x);
14 cout << "x = " << x << endl;
15 }
Punteros (cont.)
Imprime:
1 x = 47
2 a = 47
3 a = 5
4 x = 47
Como la variable a en f() es una copia, resulta que la modificacion que se
hace en f() no persiste, de manera que queda el mismo valor.
Punteros (cont.)
1 #include <iostream>
2 using namespace std;
3
4 void f(int* p) {
5 cout << "p = " << p << endl;
6 cout << "*p = " << *p << endl;
7 *p = 5;
8 cout << "p = " << p << endl;
9 }
10
11 int main() {
12 int x = 47;
13 cout << "x = " << x << endl;
14 cout << "&x = " << &x << endl;
15 f(&x);
16 cout << "x = " << x << endl;
17 }
Punteros (cont.)
Imprime:
1 x = 47
2 &x = 0065FE00
3 p = 0065FE00
4 *p = 47
5 p = 0065FE00
6 x=5
Referencias
Los punteros son muy utiles 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
dereferenciacion.
1 #include <iostream>
2 using namespace std;
3
4 void f(int& r) {
5 cout << "r = " << r << endl;
6 cout << "&r = " << &r << endl;
7 r = 5;
8 cout << "r = " << r << endl;
9 }
10
11 int main() {
12 int x = 47;
13 cout << "x = " << x << endl;
14 cout << "&x = " << &x << endl;
15 f(x); // Looks like pass-by-value,
16 // is actually pass by reference
17 cout << "x = " << x << endl;
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 92
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
18 }
Referencias (cont.)
Imprime:
1 x = 47
2 &x = 0065FE00
3 r = 47
4 &r = 0065FE00
5 r=5
6 x=5
Punteros a void
3 p = &n; // OK
4 double a;
5 p = &a; // Error
2 char c;
3 int i;
4 float f;
5 double d;
6 vp = &c;
7 vp = &i;
8 vp = &f;
9 vp = &d;
Una variable existe desde su definicion hasta la siguiente llave que cierra (}).
Eso se llama el scope de la variable.
1 // How variables are scoped
2 int main() {
3 int scp1;
4 // scp1 visible here
5 {
6 // scp1 still visible here
7 //. . . . .
8 int scp2;
9 // scp2 visible here
10 //. . . . .
11 {
12 // scp1 & scp2 still visible here
13 //. .
14 int scp3;
15 // scp1, scp2 & scp3 visible here
16 // . . .
17 } // scp3 destroyed here
18 // scp3 not available here
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 97
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
En C todas las variables deben ser definidas al comienzo del scope. En C++
se pueden definir en cualquier lugar.
1 // On-the-fly variable definitions
2 #include <iostream>
3 using namespace std;
4
5 int main() {
6 //. .
7 { // Begin a new scope
8 int q = 0; // C requires definitions here
9 //. .
10 // Define at point of use:
11 for(int i = 0; i < 100; i++) {
12 q++; // q comes from a larger scope
13 // Definition at the end of the scope:
14 int p = 12;
15 }
16 int p = 1; // A different p
17 } // End scope containing q & outer p
18 cout << "Type characters:" << endl;
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 99
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
19 while(char c = cin.get() != q) {
20 cout << c << " wasnt it" << endl;
21 if(char x = c == a | | c == b)
22 cout << "You typed a or b" << endl;
23 else
24 cout << "You typed " << x << endl;
25 }
26 cout << "Type A, B, or C" << endl;
27 switch(int i = cin.get()) {
28 case A: cout << "Snap" << endl; break;
29 case B: cout << "Crackle" << endl; break;
30 case C: cout << "Pop" << endl; break;
31 default: cout << "Not A, B or C!" << endl;
32 }
33 }
Las variables que estan fuera de todas las funciones son globales, su scope
es todo el programa, includo dentro de las funciones.
1 // == file1.cpp ==
2 // Demonstration of global variables
3 #include <iostream>
4 using namespace std;
5
6 int globe;
7 void func();
8 int main() {
9 globe = 12;
10 cout << globe << endl;
11 func(); // Modifies globe
12 cout << globe << endl;
13 }
14 // == file2.cpp ==
15 // Accessing external global variables
16 extern int globe;
17 // (The linker resolves the reference)
18 void func() {
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 101
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
19 globe = 47;
20 }
Variables locales
Las variables que existen dentro de un scope son locales, tambien se les
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 void f(int x) {
2 int a;
3 cout << "a en f(): " << a << endl;
4 cout << "&a en f(): " << &a << endl;
5 a=x;
6 cout << "a en f() despues de asignar: " << a << endl;
7 }
8
9 void g(int x) {
10 int a;
11 cout << "a en g(): " << a << endl;
12 cout << "&a en g(): " << &a << endl;
13 a=x;
14 cout << "a en g() despues de asignar: " << a << endl;
15 }
16
17 void h(int x) {
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 103
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
18 int a;
19 f(435);
20 cout << "a en h(): " << a << endl;
21 cout << "&a en h(): " << &a << endl;
22 a=x;
23 cout << "a en h() despues de asignar: " << a << endl;
24 }
25
26 int main() {
27 f(23);
28 g(45);
29 f(23);
30 g(45);
31 h(234);
32 return 0;
33 }
El resultado es:
1 [mstorti@galileo garage]$$ ./try2.bin
2 a en f(): 0
3 &a en f(): 0x7fff6df56d1c
4 a en f() despues de asignar: 23
5 a en g(): 23
6 &a en g(): 0x7fff6df56d1c
7 a en g() despues de asignar: 45
8 a en f(): 45
9 &a en f(): 0x7fff6df56d1c
10 a en f() despues de asignar: 23
11 a en g(): 23
12 &a en g(): 0x7fff6df56d1c
13 a en g() despues de asignar: 45
14 a en f(): 59
15 &a en f(): 0x7fff6df56cdc
16 a en f() despues de asignar: 435
17 a en h(): 45
18 &a en h(): 0x7fff6df56d1c
Variables estaticas
Si queremos que el area asignada a una variable local sea siempre el mismo,
entonces le agregamos el keyword static. Un ejemplo clasico es una funcion
que cuenta cuantas veces fue llamada:
1 void f() {
2 static int count=0;
3 cout << "f() fue llamada " << count << " veces" << endl;
4 cout++;
5 }
6
7 int main() {
8 for (int j=0; j<10; j++)
9 f();
10 return 0;
11 }
El resultado es:
1 [mstorti@galileo garage]$ ./try14.bin
2 f() fue llamada 0 veces
3 f() fue llamada 1 veces
4 f() fue llamada 2 veces
5 f() fue llamada 3 veces
6 f() fue llamada 4 veces
7 f() fue llamada 5 veces
8 f() fue llamada 6 veces
9 f() fue llamada 7 veces
10 f() fue llamada 8 veces
11 f() fue llamada 9 veces
12 [mstorti@galileo garage]$
Constantes
Operadores. Asignacion
Operadores matematicos
Los operadores matematicos binarios usuales son +-*/. Cada uno de ellos se
puede usar en forma de acumulacion +=, -=, *=, /=. Por ejemplo
1 x += 5;
es equivalente a
1 x = x + 5;
Operadores relacionales
Son
1 >, <, >=, <=, ==, !=
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 expr1 && expr2
entonces primero se evalua expr1 y si da falso, entonces expr2 NO se evalua,
ya que no es necesario porque la expresion logica resultara en falso de todas
formas. Eso puede ser importante, por ejemplo
1 if (n>0 && m/n!=3) . . .
esta garantizado que no dara error si n==0 ya que si es as directamente la
division por n no se hara. Lo mismo ocurre en
1 expr1 | | expr2
si la primera da verdadero.
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);
Se puede usar tambien en un lvalue. La siguiente expresion asigna al menor
de m,n el valor 23.
1 (m<n ? m : n) = 23;
Operadores de cast
Operador sizeof
6 double a;
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)
-
3 ulong x;
Estructuras
Estructuras (cont.)
Estructuras (cont.)
1 cell c1,c2,c3;
2 c1.c = a; c1.x = 1; c1.next = &c2;
3 c2.c = b; c2.x = 2; c2.next = &c3;
4 c3.c = c; c3.x = 3; c3.next = &c1;
c1
next
c='a' x=1
c3 c2
next next
c='c' x=3 c='b' x=2
Estructuras (cont.)
El resultado es
1 [mstorti@galileo garage]$$ ./try8.bin
2 cp 0x7fff571b2d20, c a, x 1
3 cp 0x7fff571b2d00, c b, x 2
4 cp 0x7fff571b2ce0, c c, x 3
cp 0x7fff571b2d20, c a, x 1
...
5
6
7 cp 0x7fff571b2d20, c a, x 1
8 cp 0x7fff571b2d00, c b, x 2
9 [mstorti@galileo garage]$$
Arrow operator
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
arbitrariamente gtype=0 para crculos, 1=cuadrados, 2=rectangulos.
1 struct shape {
2 double x,y;
3 int gtype;
4 };
Entonces una funcion que imprime la forma sera algo as como
1 void draw(shape s) {
2 if (s.gtype==0) //. . . imprime un circulo
3 else if (s.gtype==1) //. . . imprime un cuadrado
else if (s.gtype==2) //. . . imprime un rect
...
4
5
6 }
El problema con esto es que tenemos que guardar mentalmente una tabla
para saber que entero corresponda a cada forma.
Enums (cont.)
5 void draw(shape s) {
6 if (s.gtype==CIRCLE) //. . . imprime un circulo
7 else if (s.gtype==SQUARE) //. . . imprime un cuadrado
else if (s.gtype==RECTANGLE) //. . . imprime un rect
...
8
9
10 }
Enums (cont.)
Pero, como ya dijimos, es preferible no usar macros, para esto esta el enum:
1 enum GeoType { circle, square, rectangle};
2
3 struct shape {
4 double x,y;
5 GeoType gtype;
6 };
7
8 void draw(shape s) {
9 if (s.gtype==circle) //. . . imprime un circulo
10 else if (s.gtype==square) //. . . imprime un cuadrado
else if (s.gtype==rectangle) //. . . imprime un rect
...
11
12
13 }
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 especfico
1 enum GeoType { circle=5, square=10, rectangle=15};
Arreglos de estructuras
2 double x;
3 cell *next;
4 };
5
6 for (int j=0; j<4; j++)
10 &cellv[0] 140736201505632
11 &cellv[1] 140736201505648
12 &cellv[2] 140736201505664
3 sizeof(cell): 16
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 128
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
Punteros y arreglos
4 -> 0x7fff7e388420
Esto es porque el compilador solo almacena para el vector la direccion donde
comienza el area asignada al vector. Esto lo podemos verificar imprimiento la
direccion del primer elemento
1 cout << &cellv[0] << endl;
2 -> 0x7fff7e388420
Arreglos de punteros
Aritmetica de punteros
Se pueden hacer cuentas con punteros de tipo ptr = ptr + int y todas las
derivadas, por ejemplo
1 ptr = ptr + int
2 int = ptr - ptr
3 ptr += int
4 ptr++
5 ptr--
En todas estas operaciones el entero indica posiciones en el vector, no bytes.
1 int i[10];
2 double d[10];
3 int* ip = i;
4 double* dp = d;
5 cout << "ip = " << (long)ip << endl;
6 ip++;
7 cout << "ip = " << (long)ip << endl;
8 cout << "dp = " << (long)dp << endl;
9 dp++;
10 cout << "dp = " << (long)dp << endl;
produce
1 [mstorti@galileo garage]$$ ./try18.bin
2 ip = 140733418503296
3 ip = 140733418503300
4 dp = 140733418503216
5 dp = 140733418503224
Tamanos de estructuras
Cuando se usan estructuras con tipos mezclados puede ser que el tamano del
tipo combinado no sea igual a la suma de los tamanos de los tipos (pero
seguro es mayor o igual) porque el compilador tiene que alinear los tipos.
1 struct A {
2 char c;
3 double d;
4 };
da sizeof(A) -> 16, y
1 struct B { char c; double d; char c2; };
2 struct C { char c; char c2; double d; };
da
1 sizeof(B) -> 24
2 sizeof(C) -> 16
Programacion Orientada
a Objetos
Abstraccion de datos
Un contenedor de elementos de longitud arbitraria
1 #ifndef CSTASH-H
2 #define CSTASH-H
3
4 struct CStash {
5 int size; // Size of each space
6 int quantity; // Number of storage spaces
7 int next; // Next empty space
8 // Dynamically allocated array of bytes:
9 unsigned char* storage;
10 };
11
12 void initialize(CStash* s, int size);
13 void cleanup(CStash* s);
14 int add(CStash* s, const void* element);
15 void* fetch(CStash* s, int index);
16 int count(CStash* s);
17 void inflate(CStash* s, int increase);
18
19 #endif
1 struct CStash {
2 int size; // Size of each space
3 int quantity; // Number of storage spaces
4 int next; // Next empty space
5 // Dynamically allocated array of bytes:
6 unsigned char* storage;
7 };
size
used free
store
quantity
next
58 void cleanup(CStash* s) {
59 if(s->storage != 0) {
60 cout << "freeing storage" << endl;
61 delete [ ]s->storage;
62 }
63 }
lado de la memoria.
count() retorna la cantidad de elementos que hay en el contenedor.
Simplemente retorna next.
Alocacion dinamica de memoria: Como no sabemos en principio que
tamano va a tomar el area de memoria vamos alocando dinamicamente
con el operador new
1 new unsigned char[newBytes];
En general se puede hacer
1 t = new Type; // aloca un solo objeto
Resultado:
1 [mstorti@galileo garage]$ ./trycstash.bin
2 fetch(&intStash, 0) = 0
3 fetch(&intStash, 1) = 1
4 fetch(&intStash, 2) = 2
fetch(&intStash, 3) = 3
...
5
6
7 fetch(&intStash, 97) = 97
8 fetch(&intStash, 98) = 98
9 fetch(&intStash, 99) = 99
10 0: #include "./cstash.h"
11 1: #include <fstream>
12 2: #include <iostream>
3: #include <string>
...
13
14
15 37: cleanup(&stringStash);
16 38: return 0;
17 39: }
18 freeing storage
19 freeing storage
20 [mstorti@galileo garage]$
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 148
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
POO basica
1 struct Stash {
2 int size; // Size of each space
3 int quantity; // Number of storage spaces
4 int next; // Next empty space
5 // Dynamically allocated array of bytes:
6 unsigned char* storage;
7 // Functions!
8 void initialize(int size);
9 void cleanup();
10 int add(const void* element);
11 void* fetch(int index);
12 int count();
13 void inflate(int increase);
14 };
57 void Stash::cleanup() {
58 if(storage != 0) {
59 cout << "freeing storage" << endl;
60 delete [ ]storage;
61 }
62 }
6 Stash s1;
7 cout << "&s1: " << &s1 << endl;
8 s1.initialize();
Imprimen el mismo puntero.
22 ifstream in("CppLibTest.cpp");
23 assure(in, "CppLibTest.cpp");
24 string line;
25 while(getline(in, line))
26 stringStash.add(line.c-str());
27 int k = 0;
28 char* cp;
29 while((cp =(char*)stringStash.fetch(k++)) != 0)
30 cout << "stringStash.fetch(" << k << ") = "
31 << cp << endl;
32 intStash.cleanup();
33 stringStash.cleanup();
34 }
Inclusion de headers
No hay problema con las funciones, pero si con las estructuras (y clases).
Se utiliza un mecanismo con macros para evitar la doble inclusion.
Podemos usar los macros para incluir condicionalmente partes del
codigo.
1 #define FLAG
2
3 #ifdef FLAG
4 //. . .
5 #else
6 //. . .
7 #endif
Notar que es muy diferente este condicional del preprocesador que el
if-else de C++. En el del preprocesador solo uno de los bloques se
compila. Quiere decir que se puede usar para usar diferentes pedazos de
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 159
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
3 #else
5 #endif
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.
1 #include <stash.h>
2 #include <stash.h> // no es incluido esta vez!!
El macro centinela STASH_H debe ser unico para ese archivo. Si otro
archivo usa el mismo macro centinela entonces sus declaraciones no son
incluidas
1 #include <libreria1/stash.h>
2 #include <libreria2/stash.h> // Error: este no es incluido
Deberian usar LIBRERIA1_STASH_H y LIBRERIA2_STASH_H.
Estructuras enlazadas
1 struct Link {
2 void* data;
3 Link* next;
4 void initialize(void* dat, Link* nxt);
5 };
6
7 struct Stack {
8 Link *head;
9 void initialize();
10 void push(void* dat);
11 void* peek();
12 void* pop();
13 void cleanup();
14 };
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 slide 165
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
11 void cleanup();
12 };
Notar que al definir el tipo Link en la misma declaracion del tipo se define
un puntero Link *head a la primera celda. Por supuesto se puede hacer
por separado tambien
struct Link {
...
1
2
3 };
4 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 funcion de inicializacion
initialize().
Link no tiene cleanup(), el mismo usario es responsable de liberar el
espacio apuntado por data, si existe.
24
25 void* Stack::pop() {
26 if(head == 0) return 0;
27 void* result = head->data;
28 Link* oldHead = head;
29 head = head->next;
30 delete oldHead;
31 return result;
32 }
33
34 void Stack::cleanup() {
35 require(head == 0, "Stack not empty");
36 }
Uso de Stack
1 // Test of nested linked list
2 #include "Stack.h"
3 #include ". ./require.h"
4 #include <fstream>
5 #include <iostream>
6 #include <string>
7 using namespace std;
8
9 int main(int argc, char* argv[ ]) {
10 requireArgs(argc, 1); // File name is argument
11 ifstream in(argv[1]);
12 assure(in, argv[1]);
13 Stack textlines;
14 textlines.initialize();
15 string line;
16 // Read file and store lines in the Stack:
17 while(getline(in, line))
18 textlines.push(new string(line));
19 // Pop the lines from the Stack and print them:
20 string* s;
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 169
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
21 while((s = (string*)textlines.pop()) != 0) {
22 cout << *s << endl;
23 delete s;
24 }
25 textlines.cleanup();
26 }
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 funcion 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 codigo y prevenir la colision de nombres, la OOP
(Programacion Orientada a Objetos) es mucho mas que esto.
Ocultando la implementacion
Amistad (Friendship)
20 i = 0;
21 }
22
23 void g(X* x, int i) {
24 x->i = i;
25 }
26
27 void Y::f(X* x) {
28 x->i = 47;
29 }
30
31 struct Z {
32 private:
33 int j;
34 public:
35 void initialize();
36 void g(X* x);
37 };
38
39 void Z::initialize() {
40 j = 99;
41 }
42
43 void Z::g(X* x) {
44 x->i += j;
45 }
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 180
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
46
47 void h() {
48 X x;
49 x.i = 100; // Direct data manipulation
50 }
51
52 int main() {
53 X x;
54 Z z;
55 z.g(&x);
56 }
El estandar dice que en principio una clases anidada no tienen que ser
necesariamente amiga de la clase externa.
1 struct E {
2 private:
3 int x;
4 struct B { };
5 struct I {
6 private:
7 B b; // error1: E::B is private
8 int y;
9 void f(E* p, int i) {
10 p->x = i; // error2: E::x is private
11 }
12 };
13 int g(I* p) { return p->y; } // error3: I::y is private
14 };
Sin embargo en la practica el GCC da acceso a la clase externa a la clase
interna, pero no al reves. Es decir da error en 1 y 2, pero no en 3.
Object layout
Una de las condiciones de diseno de C++ fue que codigo valido en C debera
compilar sin problemas en C++. Por esto las construcciones de tipo struct
tienen a todos sus miembros publicos.
Cuando el compilador organiza los datos dentro del objeto los guarda en
memoria en forma contigua, en el orden en el que estan 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
publicos de la clase) tiene sentido solo en el momento de compilacion. Una
vez que el codigo fuente es convertido a codigo de maquina dos estructuras
que difieren solo en cuanto a sus secciones private y public son
indistinguibles entre s, a menos del efecto discutido previamente de la
disposicion en la memoria (object layout).
Clases
Controlar el acceso a los miembros de una estructura es parte de lo que se
llama ocultar la implementacion (implementation hiding). Esto es un
concepto clave en OOP.
En OOP se trata de ocultar lo mas posible los miembros de la estructura, por
eso lo deseable sera 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 class A {
2 int i,j,k;
3 public:
4 double z;
5 void f();
6 };
7
8 struct B {
9 private:
10 int i,j,k;
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 184
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
11 public:
12 double z;
13 void f();
14 };
15
16 struct C {
17 double z; // salvo por el object layout
18 void f();
19 private:
20 int i,j,k;
21 };
Clases (cont.)
Vemos la clase Stash ahora con control de acceso. Todos los datos son
privados. La funcion inflate() tambien ya que solo es usada internamente.
1 class Stash {
2 int size; // Size of each space
3 int quantity; // Number of storage spaces
4 int next; // Next empty space
5 // Dynamically allocated array of bytes:
6 unsigned char* storage;
7 void inflate(int increase);
8 public:
9 void initialize(int size);
10 void cleanup();
11 int add(void* element);
12 void* fetch(int index);
13 int count();
14 };
Clases (cont.)
En Stack ahora hacemos que toda la estructura Link sea privada o sea solo es
accesible desde las funciones miembro de Stack.
1 class Stack {
2 struct Link {
3 void* data;
4 Link* next;
5 void initialize(void* dat, Link* nxt);
6 }* head;
7 public:
8 void initialize();
9 void push(void* dat);
10 void* peek();
11 void* pop();
12 void cleanup();
13 };
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.
Podramos tambien declararla como clase, pero entonces deberamos
declarar friend a Stack.
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 187
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
20 void StashWrapper::cleanup() {
21 stash->cleanup();
22 delete stash;
23 }
24
29 //. . .
Inicializacion y cleanup
5 void f() {
6 A a; // a is created -> do initialization
7 // Usar a . . .
8 // . . .
9 // . . .
10 } // a is destroyed -> do cleanup
Para esto debe haber dos funciones (una de inicializacion y otra de cleanup)
que tengan nombres especiales ya que deben ser llamadas automaticamente
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 class A {
2 public:
3 A() { /*. . .*/ }
4 // . . .
5 };
6
7 void f() {
8 A a; // a is created -> calls ctor A::A()
9 // Usar a . . .
10 // . . .
11 }
El constructor
El destructor
18 Tree::Tree() {
19 cout << "inside Tree destructor" << endl;
20 printsize();
21 }
22
23 void Tree::grow(int years) {
24 height += years;
25 }
26
27 void Tree::printsize() {
28 cout << "Tree height is " << height << endl;
29 }
30
31 int main() {
32 cout << "before opening brace" << endl;
33 {
34 Tree t(12);
35 cout << "after Tree creation" << endl;
36 t.printsize();
37 t.grow(4);
38 cout << "before closing brace" << endl;
39 }
40 cout << "after closing brace" << endl;
41 } ///:
El destructor (cont.)
17 int retval = 0;
18 cin >> retval;
19 require(retval != 0);
20 int y = retval + 3;
21 G g(y);
22 }
56 Stash::Stash() {
57 if(storage != 0) {
58 cout << "freeing storage" << endl;
59 delete [ ]storage;
60 }
61 }
1 // With constructors/destructors
2 #ifndef STACK3-H
3 #define STACK3-H
4
5 class Stack {
6 struct Link {
7 void* data;
8 Link* next;
9 Link(void* dat, Link* nxt);
10 Link();
11 }* head;
12 public:
13 Stack();
14 Stack();
15 void push(void* dat);
16 void* peek();
17 void* pop();
18 };
32 Stack::Stack() {
33 require(head == 0, "Stack not empty");
34 } ///:
Initializacion de agregados
Inicializacion de estructuras
1 struct X {
2 int i;
3 float f;
4 char c;
5 };
6
7 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} };
Sobrecarga de funciones
Otra posibilidad es que los dos ctores previos sean el mismo con un
argumento por default para el tamano
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)
Constantes
Constantes (cont.)
Constantes (cont.)
Const en clases
Chapter 5
Funciones inline
Cada vez que hay una llamada a funcion hay un costo adicional de pasar
los argumentos por el stack a la funcion y hacer un jump de assemble.
Para evitar esto podemos usar el keyword inline que indica al compilador
que queremos que el codigo de esa funcion sea replicado en cada punto
en que lo llamamos.
La ventaja, como dijimos, es la eficiencia, se evita el mecanismo de
llamado a funcion en assemble.
La desventaja es que el codigo binario de la funcion aparece duplicado en
cada punto, con lo cual el ejecutable se hace mas grande. Tambien
implica que el codigo de la funcion 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 despues hacer la funcion realmente inline o no. A veces puede
hacerla no inline porque es muy compleja (e.g. tiene lazos) o porque en
algun punto se toma la direccion de la funcion.
Funciones definidas en la misma clase (y por lo tanto en el header
normalmente) son candidatas a ser promovidas a inline por el compilador.
1 // file: a.hpp
2 // max es explicitamente inline
3 // (Notar que si no es inline daria error
4 // al linkeditar por multiple definicion de max())
5 inline double max(double x,double y) {
6 return (x>y ? x : y);
7 }
8
9 class A {
10 private:
11 int maxsize;
12 public:
13 // Accessors: automaticamente inline
14 int get-maxsize() { return maxsize; }
15 void set-maxsize(int maxsz) { maxsize=maxsz; }
16 //. . .
17 };
Otra forma que habra para evitar el llamado a funciones sera no definir la
funcion sino que en cada punto que se usa incluir explcitamente su codigo.
Para evitar esto una forma que exista 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 codigo final se reemplaze la
llamada a MAX por la expansion del macro.
OJO, como pasa en general con los macros son peligrosos, Por ejemplo
1 int l = MAX(j++,k);
3 // Hace a=11!!
4 a = SQUARE(5+1)
Especificaciones de linkedicion
Referencias en C++
Vimos el concepto de referencia, basicamente son punteros inteligentes que
se autodereferencian.
Se pueden implementar funciones que modifican sus argumentos mediante
punteros
1 void inc(int *x) {
2 *x = *x + 1,
}
...
3
4
5 int a=2;
6 inc(&a); // hace a=3
pero son engorrosos porque hay que ir derereferenciando el puntero. Con
referencias es mucho mejor,
1 void inc(int &x) {
2 x = x + 1,
}
...
3
4
5 int a=2;
6 inc(a); // hace a=3
Otro uso es para crear aliases locales para modificar una parte de un
contenedor mas grande, por ejemplo un arreglo de varias dimensiones
(tambien puede ser con los contenedores de las STL)
1 class A {
2 // . . . .
3 void f(); // modifica a *this
4 };
5
6 // arreglo multidimensional de As
7 A av[100][100][100];
8 // Un elemento particular de av
9 int i,j,k;
10 //. . .
11 av[i][j][k].f();
7 ap->f();
Esto es eficiente, y compacto pero hay que andar dereferenciando ap. Todava
mejor es usar referencias
1 // arreglo multidimensional de As
2 A av[100][100][100];
3 // Un elemento particular de av
4 int i,j,k;
5 A &a = av[i][j][k];
6
7 a.f();
Es eficiente, limpio, y a se manipula como un objeto mas de la clase.
4 a = av[i][j][k];
Sobrecarga de operadores
5 class HandleToA {
6 A &operator*() { . . . } // dereferenciacion (2)
7 };
8
9 A a1, a2, a3;
10 HandleToA p;
11
23 int i = 1, j = 2, k = 3;
24 k += i + j;
25 cout << "user-defined types:" << endl;
26 Integer ii(1), jj(2), kk(3);
27 kk += ii + jj;
28 }
22 // Prefix:
23 friend const Integer&
24 operator++(Integer& a);
25 // Postfix:
26 friend const Integer
27 operator++(Integer& a, int);
28 // Prefix:
29 friend const Integer&
30 operator--(Integer& a);
31 // Postfix:
32 friend const Integer
33 operator--(Integer& a, int);
34 };
35
36 // Global operators:
37 const Integer& operator+(const Integer& a) {
38 cout << "+Integer\n";
39 return a; // Unary + has no effect
40 }
41 const Integer operator-(const Integer& a) {
42 cout << "-Integer\n";
43 return Integer(-a.i);
44 }
45 const Integer operator(const Integer& a) {
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 243
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
69 }
70 // Prefix; return decremented value
71 const Integer& operator--(Integer& a) {
72 cout << "--Integer\n";
73 a.i--;
74 return a;
75 }
76 // Postfix; return the value before decrement:
77 const Integer operator--(Integer& a, int) {
78 cout << "Integer--\n";
79 Integer before(a.i);
80 a.i--;
81 return before;
82 }
83
84 // Show that the overloaded operators work:
85 void f(Integer a) {
86 +a;
87 -a;
88 a;
89 Integer* ip = &a;
90 !a;
91 ++a;
92 a++;
93 --a;
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 245
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
94 a--;
95 }
96
97 // Member functions (implicit this):
98 class Byte {
99 unsigned char b;
100 public:
101 Byte(unsigned char bb = 0) : b(bb) {}
102 // No side effects: const member function:
103 const Byte& operator+() const {
104 cout << "+Byte\n";
105 return *this;
106 }
107 const Byte operator-() const {
108 cout << "-Byte\n";
109 return Byte(-b);
110 }
111 const Byte operator() const {
112 cout << "Byte\n";
113 return Byte(b);
114 }
115 Byte operator!() const {
116 cout << "bang Byte\n";
117 return Byte(!b);
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 246
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
118 }
119 Byte* operator&() {
120 cout << "&Byte\n";
121 return this;
122 }
123 // Side effects: non-const member function:
124 const Byte& operator++() { // Prefix
125 cout << "++Byte\n";
126 b++;
127 return *this;
128 }
129 const Byte operator++(int) { // Postfix
130 cout << "Byte++\n";
131 Byte before(b);
132 b++;
133 return before;
134 }
135 const Byte& operator--() { // Prefix
136 cout << "--Byte\n";
137 --b;
138 return *this;
139 }
140 const Byte operator--(int) { // Postfix
141 cout << "Byte--\n";
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 247
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
45 operator-=(Integer& left,
46 const Integer& right);
47 friend Integer&
48 operator*=(Integer& left,
49 const Integer& right);
50 friend Integer&
51 operator/=(Integer& left,
52 const Integer& right);
53 friend Integer&
54 operator%=(Integer& left,
55 const Integer& right);
56 friend Integer&
57 operator=(Integer& left,
58 const Integer& right);
59 friend Integer&
60 operator&=(Integer& left,
61 const Integer& right);
62 friend Integer&
63 operator|=(Integer& left,
64 const Integer& right);
65 friend Integer&
66 operator>>=(Integer& left,
67 const Integer& right);
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 252
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
68 friend Integer&
69 operator<<=(Integer& left,
70 const Integer& right);
71 // Conditional operators return true/false:
72 friend int
73 operator==(const Integer& left,
74 const Integer& right);
75 friend int
76 operator!=(const Integer& left,
77 const Integer& right);
78 friend int
79 operator<(const Integer& left,
80 const Integer& right);
81 friend int
82 operator>(const Integer& left,
83 const Integer& right);
84 friend int
85 operator<=(const Integer& left,
86 const Integer& right);
87 friend int
88 operator>=(const Integer& left,
89 const Integer& right);
90 friend int
91 operator&&(const Integer& left,
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 253
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
444
445 void k(Byte& b1, Byte& b2) {
446 b1 = b1 * b2 + b2 % b1;
447
448 #define TRY2(OP) \
449 out << "b1 = "; b1.print(out); \
450 out << ", b2 = "; b2.print(out); \
451 out << "; b1 " #OP " b2 produces "; \
452 (b1 OP b2).print(out); \
453 out << endl;
454
455 b1 = 9; b2 = 47;
456 TRY2(+) TRY2(-) TRY2(*) TRY2(/)
457 TRY2(%) TRY2() TRY2(&) TRY2(|)
458 TRY2(<<) TRY2(>>) TRY2(+=) TRY2(-=)
459 TRY2(*=) TRY2(/=) TRY2(%=) TRY2(=)
460 TRY2(&=) TRY2(|=) TRY2(>>=) TRY2(<<=)
461 TRY2(=) // Assignment operator
462
463 // Conditionals:
464 #define TRYC2(OP) \
465 out << "b1 = "; b1.print(out); \
466 out << ", b2 = "; b2.print(out); \
467 out << "; b1 " #OP " b2 produces "; \
468 out << (b1 OP b2); \
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 269
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
471 b1 = 9; b2 = 47;
472 TRYC2(<) TRYC2(>) TRYC2(==) TRYC2(!=) TRYC2(<=)
473 TRYC2(>=) TRYC2(&&) TRYC2(| |)
474
7 // . . .
8 Integer R,L;
9 L += R;
Chapter
3 A *p = (A*)malloc(sizeof(A));
4 A-initialize(p);
5 // . . . . usa *p
6 A-destroy(p);
7 free(p);
Hay varios puntos donde esto puede fallar, por un error del programador:
En C++ se trata que todas estas acciones sean hechas en lo posible en forma
automatica por el operador. Para esto las funciones malloc() y free() (que
despues de todo son funciones de librera es decir que no son parte del
lenguaje) son reemplazadas por operadores intrnsecos del lenguaje: new y
delete.
1 A *p = new A;
2 // . . . usa *p
3 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.
6 int n=100;
7 A a[n]; // ERROR
El ultimo debera dar error de compilacion aunque dependiendo del
compilador puede que no lo de (sera una extension del compilador). De
todas formas siempre es mas restrictivo que alocar con new porque el arreglo
es desalocado y destruido cuando termina su scope.
Memory exhaust
9 // version nothrow
10 int *p = new(std::nothrow) int[N];
11 if (!p) {
12 // error. . .
13 }
Composicion
Composicion (cont.)
La idea es que las clases de objetos se pueden usar como nuevos tipos, por
lo tanto se pueden usar en la composicion de otros tipos
1 class B {
2 private:
3 int k;
4 double z;
5 public:
6 A a;
7 void g();
8 };
En este caso B::a es publico, de forma que los metodos publicos de A tambien
se pueden llamar sobre este campo, es decir
1 B b;
2 b.a.f(); // OK
Herencia
Otra forma de elaborar clases mas complejas a partir de otras mas simples es
por herencia.
1 class C : public A {
2 int k;
3 double z;
4 public:
5 void g();
6 };
Se dice que C es una clase derivada de A y A es la clase base de C.
Los metodos de A se pueden llamar ahora tambien sobre C. en este caso
estamos diciendo C es como A pero tiene algunas cosas adicionales. Al hacer
composicion estamos diciendo que C contiene a un objeto de tipo A.
Herencia (cont.)
Herencia (cont.)
4 class B {
5 A a1,a2;
6 X x;
7 // . . .
8 };
Redefinicion de metodos
Que pasa si la clase derivada tiene un metodo con el mismo nombre que la
clase base? Con composicion no hay problema
1 class A {
2 public:
3 void f();
4 };
5
6 class B {
7 public:
8 A a;
9 void f();
10 };
11
12 B b;
13 b.f(); // llama la f de B
14 b.a.f(); // llama la f de A
6 class B : public A {
7 public:
8 void f();
9 };
10
11 B b;
12 b.f(); // llama la f de B
13 b.A::f(); // llama la f de A
Herencia protegida
18 int main() {
19 Derived d;
20 d.change(10);
21 }
Upcasting
Polimorfismo
Nosotros queremos definir clases base que son genericas (por ejemplo
Matrix) y plantear algoritmos/operaciones genericos para las mismas (por
ejemplo GradConj()). Estos algoritmos toman un puntero a la clase base y
llaman operaciones genericas sobre la misma (por ejemplo el producto matriz
vector MatVec()). Luego podemos definir clases derivadas para las matrices
de distinto tipo (llena, banda, sparse, simetrica...) La idea es que cuando el
algoritmo generico GradConj() llama al metodo MatVec()), esta llamada sea
despachada a la funcion correspondiente en la clase derivada.
Polimorfismo (cont.)
16 Base *p = d2;
17 p->f(); // llama a Derived::f()
Z xb
I1 = f (x) dx,
xa
Z yb Z xb
I2 = f (x, y) dx dy,
ya xa
Z zb Z yb Z xb
I3 = f (x, y, z) dx dy dz,
za ya xa
21 finteg=0.0;
22 for (int j=0; j<N; j++) {
23 double x = j*h;
24 double f = fp->eval(x);
25 finteg += 2.0*f;
26 finteg += 4.0*fp->eval(x+h2);
27 }
28 finteg -= fp->eval(xa);
29 finteg += fp->eval(xb);
30 finteg *= h/6.0;
31 return finteg;
32 }
33 };
54 int main() {
55 int N=10;
56
57 // 2D integration example
58 integral2d-t int2d(N,0.0,1.0,0.0,1.0,&fun);
59 cout << "integral(x,y) = " << int2d.integral() << endl;
60
61 return 0;
62 }
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 funcion 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 implementacion hemos hecho estas clases globales y totalmente
publicas 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 funcion g().
23 };
24
25 // Integral of a one var funct over an interval
26 class integral1d-t {
27 private:
28 int N; // Nbr of integration pts
29 double xa,xb; // integration interval
30 scalarfun1d-t *fp; // ptr to function
31 public:
32 // Ctor, set values
33 integral1d-t(int Na=0,double xaa=NAN,
34 double xba=NAN,scalarfun1d-t *fpa=NULL) {
35 set(Na,xaa,xba,fpa);
36 }
37 // Set values
38 void set(int Na,double xaa,double xba,scalarfun1d-t *fpa) {
39 N=Na; xa=xaa; xb=xba; fp=fpa;
40 }
41 // Computes the integral using Simpsons rule
42 double integral() {
43 double
44 h = (xb-xa)/N,
45 h2 = h/2.0,
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 305
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
46 finteg=0.0;
47 for (int j=0; j<N; j++) {
48 double x = j*h;
49 double f = fp->eval(x);
50 finteg += 2.0*f;
51 finteg += 4.0*fp->eval(x+h2);
52 }
53 finteg -= fp->eval(xa);
54 finteg += fp->eval(xb);
55 finteg *= h/6.0;
56 return finteg;
57 }
58 };
59
60
61 // Integral of 2var functions over a rectangle
62 class integral2d-t {
63 private:
64 scalarfun2d-t *f2dp; // Ptr to 2var funct
65 integral1d-t int1dy, int1dx; // integrals over x and y
66 // For a given y gives the function fy(x) = f(x,y)
67 class fy-t : public scalarfun1d-t {
68 double y;
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 306
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
114 };
115
116
117 // Integral of 3var functions over a cube
118 class integral3d-t {
119 private:
120 scalarfun3d-t *f3dp; // Ptr to 3var funct
121 integral2d-t int2dxy; // integral over x,y
122 integral1d-t int1dz; // integral over z
123 // For a given z gives the function fz(x,y) = f(x,y,z)
124 class fz-t : public scalarfun2d-t {
125 double z;
126 integral3d-t *i3dp; // ptr to calling class
127 friend class integral3d-t;
128 public:
129 double eval(double x,double y) {
130 return i3dp->f3dp->eval(x,y,z);
131 }
132 } fz;
133 // For a given z, gives g(z) = integral over x,y:
134 // g(z) = int-{x=xa}xb int-{y=ya}yb f(x,y,z) dx dy
135 class g-t : public scalarfun1d-t {
136 integral3d-t *i3dp; // ptr to calling class
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 309
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
160 int1dz.set(N,za,zb,&g);
161 }
162 integral3d-t(int Na=0, // Ctor
163 double xaa=NAN,double xba=NAN,
164 double yaa=NAN,double yba=NAN,
165 double zaa=NAN,double zba=NAN,
166 scalarfun3d-t *f3dpa=NULL) {
167 set(Na,xaa,xba,yaa,yba,zaa,zba,f3dpa);
168 g.i3dp = this;
169 fz.i3dp = this;
170 }
171 double integral() { // Comp 3D integral. Integrates over z
172 return int1dz.integral();
173 }
174 };
175
176
177 // User code starts here----
178 // Specific 1var function to be integrated
179 class fun-t : public scalarfun1d-t {
180 public:
181 double eval(double x) {
182 // Must give (2/pi) = 0.63662
183 return sin(0.5*M-PI*x);
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 311
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
184 }
185 } fun;
186
187 // Specific 2var function to be integrated
188 class fun2-t : public scalarfun2d-t {
189 public:
190 double eval(double x,double y) {
191 // Must give (2/pi)2 = 0.40528
192 return sin(0.5*M-PI*x)*sin(0.5*M-PI*y);
193 }
194 } fun2;
195
196 // Specific 3var function to be integrated
197 class fun3-t : public scalarfun3d-t {
198 public:
199 double eval(double x,double y,double z) {
200 // Must give (2/pi)3 = 0.25801
201 return sin(0.5*M-PI*x)
202 *sin(0.5*M-PI*y)*sin(0.5*M-PI*z);
203 }
204 } fun3;
205
206 int main() {
207 int N=10;
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 312
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
17 public:
18 double eval(double y) { // wrapper pass to calling class
19 return i2dp->geval(y);
20 }
21 } g;
22 double geval(double y) {
23 // Integrates over x for y=cnst
24 fy.y = y;
25 return int1dx.integral();
26 }
27 int N; // Nbr of integr segments
28 double xa,xb,ya,yb; // rectangle corners
29 friend class fy-t;
30 friend class g-t;
31 public:
32 void set(int Na=0,double xaa=NAN,double xba=NAN,
33 double yaa=NAN,double yba=NAN,
34 scalarfun2d-t *f2dpa=NULL) {
35 N = Na; xa=xaa; xb=xba; ya=yaa; yb=yba;
36 f2dp = f2dpa;
37 int1dy.set(N,ya,yb,&g);
38 int1dx.set(N,xa,xb,&fy);
39 }
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 315
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
Integral 3D
39 scalarfun3d-t *f3dpa) {
40 N = Na; xa=xaa; xb=xba; ya=yaa; yb=yba; za=zaa; zb=zba;
41 f3dp = f3dpa;
42 int2dxy.set(N,xa,xb,ya,yb,&fz);
43 int1dz.set(N,za,zb,&g);
44 }
45 integral3d-t(int Na=0, // Ctor
46 double xaa=NAN,double xba=NAN,
47 double yaa=NAN,double yba=NAN,
48 double zaa=NAN,double zba=NAN,
49 scalarfun3d-t *f3dpa=NULL) {
50 set(Na,xaa,xba,yaa,yba,zaa,zba,f3dpa);
51 g.i3dp = this;
52 fz.i3dp = this;
53 }
54 double integral() { // Comp 3D integral. Integrates over z
55 return int1dz.integral();
56 }
57 };
51 int main() {
52 stride-t stride(10,0,1);
53 cout << "sum(0. .9): " << vecsum(stride) << endl;
54
55 vector<double> a;
56 double p=3; int N=10;
57 a.resize(N);
58 for (int j=0; j<N; j++) a[j] = pow(j,p);
59 vecwrap-t vw(a);
60 cout << "sum-{j=0}{j=9} x3 (with vecwrap): "
61 << vecsum(vw) << endl;
62
63 fun-t f;
64 cout << "sum-{j=0}{j=9} x3 (with fun-t): "
65 << vecsum(f) << endl;
66
67 return 0;
68 }
Contenedores de la
librera STL
La clase vector
La clase vector
1 double sum = 0;
2 for (int j=0; j<v.size(); j++) sum += v[j];
Pero esto se puede usar solo con vector, con iteradores se puede iterar
sobre casi cualquiera de los otros contenedores.
Los iterators de vector<> soportan aritmetica de punteros (como los
punteros). Esto es solo valido para los iterators de vector, no para list<>
o map<> por ejemplo.
Se puede insertar un elemento en cualquier posicion del vector, sin
embargo esto puede ser costoso (O(n)).
1 vector<double> v(100,0);
2 q = v.begin() + 50; // Apunta al elemento v[50]
3 v.insert(q,33); // Inserta un 33 en la posicion 50
Despues de esto el vector tiene 101 elementos. Por supuesto esto implica
no solo redimensionar el vector sino tambien copiar los elementos en
[50,99] a [51,100].
Para pasar los vectores como argumentos conviene hacerlo a traves de
referencias para evitar la copia. Para indicar que la funcion no modifica al
vector se debe declarar el argumento como const.
1 double vecsum(const vector<double> &w) {
Pero entonces se debe iterar sobre el mismo con un const_iterator
Facultad de Ingeniera y Ciencias Hdricas FICH - UNL slide 329
((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))
Programacion en C++ para Ciencia e Ingeniera, por M.Storti, L. Dalcn, Rodrigo Paz
La clase list
3 L1.splice(r,L2,p,q));
inserta todo el rango [p,q) de L2 en la posicion r de L1. MUY EFICIENTE
(O(1)).
list<> tambien tiene swap. De hecho swap se puede implementar para list
en terminos de splice
1 list<int> L1,L2,tmp;
2 // Pone elementos en L1, y L2
3 tmp.splice(tmp.begin(),L1.begin(),L1.end());
4 L1.splice(L1.begin(),L2.begin(),L2.end());
5 L2.splice(L2.begin(),tmp.begin(),tmp.end());
Toda la operacion es O(1), por lo tanto es tan eficiente como swap. Pero
splice() es mas general (es como swap pero para pedazos de lista).
vector no tiene splice().
Los headers son #include <list> y <slist>
La clase set
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.
Estan en el header <algorithm>. No son metodos 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
union de los mismos (sin elementos duplicados) en C. De la forma en que
esta llamada arriba hace la operacion estandar de union.
C =AB
1 C.clear();
2 set-difference(A.begin(),A.end(),B.begin(),B.end(),
3 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).
La clase map
2 while (q!=sueldos.end()) {
3 cout << "DNI " << q->first << ", sueldo " << q->second << endl;
4 q++;
5 }
Notar que los iteradores iteran sobre los pares clave, valor, de hecho son
estruturas de tipo pair<int,double>.
El contenedor pair es el mas basico 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.
1 pair<int,double> p;
2 p.first = 23;
3 p.second = 234.56;
Tambien se puede declarar pair<int,double> p(23,45.67);
El map tiene un efecto colateral no comun que es que si indexamos por
una clave que no tiene asignado un valor entonces crea una asginacion
poniendo como imagen el constructor por defecto de range_t
1 map<int,string> M;
2 string z = M[5]; // Asigna z= string vacio !!!
Algoritmos