Está en la página 1de 280

C++ Avanzado

Tema 5

TACC II Curso 2008/09 1

Indice
Tipos y Declaraciones.
Declaraciones. Declaraciones Tipos. Operadores. Conversiones de tipos bsicos. Instrucciones C++. Constantes. Gestin de memoria. Funciones. Clases. Cl Espacios de Nombres. Biblioteca Estndar (STL). ( ) Herencia. Manejo de Errores. Entrada/Salida. E t d /S lid
2

Declaracin de Variables
Declaracin vs. Definicin
En C++ antes de usar un nombre (un identificador) hay que declararlo (especificar su tipo).
char ch; const double pi = 3 i 3.141592654; 926 double sqrt(double); struct User; struct D t {i t d m, y; } t t Date {int d, }; extern int error_number;

Algunas declaraciones pueden ser adems definiciones (definen una entidad para el identificador):
char ch; // def.: cantidad de memoria const d bl pi = ...; double i // def.: valor. double sqrt(double); // no def. struct User; // no def. struct str ct Date {int d m y;};// def d, m, } // def.: n e o tipo nuevo tipo. extern int error_number; // no def. 3

Declaracin de Variables
Declaracin vs. Definicin

Debe haber exactamente una definicin por cada declaracin. Puede haber varias declaraciones, que deben coincidir en el tipo de la entidad a la que se refieren refieren.
int count; int count; // error: redefinicion

extern int error_number; extern short error number; // error: tipos distintos error_number;

Estructura de una Declaracin


Consta de cuatro partes: C t d t t Un especificador opcional (ej.: virtual, extern, static, volatile) Un tipo base (ej.: char, int). Un declarador. Consta de un nombre y opcionalmente unos operadores:
* *const & [] () p puntero, puntero constante, referencia, array funcin p j prefijo. prefijo. prefijo. postfijo. postfijo.

Un inicializador opcional.

Excepto funciones y espacios de nombres una declaracin termina nombres, en punto y coma.
char * beers[]={mahou, franciscaner, kostritzer}; // tipo base: char // declarador: * beers[] // inicializador: {mahou, franciscaner, kostritzer};

Ejercicios
Cmo se declaran e incializan?
Sea:
int f(); int g(); int a=1, b=2, c=3, &d=c; , , ,

Un array de punteros a int, inicializado a las variables a-d.


int *e[]={&a, &b, &c, &d};

Un array de punteros constantes a int, inicializado a las variables a-d. y


int * const e[] ={&a, &b, &c, &d};

Un array de punteros a funciones que devuelven int, inicializado a f g int f, g.


int (*e[2])() = {&f, &g};

mbito de una Declaracin


En C++ E C una d l declaracin d una variable l i de i bl local se puede l d hacer en cualquier lugar de un bloque y es vlida hasta el final del mismo.
En C se debe hacer al inicio del bloque.

En sub-bloques se pueden definir variables locales con el mismo nombre (acceso con operador :: explicado ::, en apartado de namespaces). Toda variable declarada dentro de un bloque es auto (desaparece al finalizar el bloque) por defecto.
7

mbito de una Declaracin


Ejemplo
#include <iostream> char c = 'A'; // c global, declarada fuera de main void main ( ) { char c = 'B'; // c local a main { char c = 'D'; // c local al bloque interno std::cout << c; // c es la c local al b. i. std::cout << ::c; // ::c es la c global } }

mbito de una Declaracin


Otros usos de static Ot d t ti
Variable local de una funcin
Conserva su valor en sucesivas ll C l i llamadas. d

Variable global
Visible en un fichero desde el lugar en que se declara hasta final de fichero.

Variable global externa (extern)


En un fichero se define (opcionalmente un valor):
int numero [= valor];

En otro fichero se declara (se utiliza) :


extern int numero; t i t
9

Tipos Bsicos
Tipos d d t Ti de datos:
short (2), long (4), int (4) float (4) d bl (8) fl (4), double bool (C++) (1).

Arrays
Una variable const puede ser la dimensin de un array como memoria esttica (incorrecto en C)
La dimensin de un array con memoria dinmica puede ser cualquier expresin

10

Enumeraciones, Enumeraciones estructuras y uniones


enum Color {verde 0 amarillo 2 rojo}; {verde=0, amarillo=2, enum Color semforo; Color semaforo; //(incorrecto en C) union Numero { long x; char y; }; union Numero n; ; Numero n; //(incorrecto en C) struct Libro {. . .}; struct Libro novela; Libro novela; //(incorrecto en C)

11

Estructuras
Inicializacin

Se pueden inicializar con el mismo estilo que un array.


struct address { char * name; long int number; char state[2]; h t t [2] long zip; }; address jd = {"Jim Dandy", 61, {'N', 'J'}, 8899};
12

Estructuras
Equivalencia

Son distintos tipos aunque t S di ti t ti tengan l mismos los i miembros.


struct S1 { int a; }; struct S2 { int a; }; void main() { S1 x; ; S2 y = x; // error }

13

Operadores
Operadores lgicos :
! (negacin), &&, ||
En Visual C++ se puede utilizar los macros: not, and, or
Hace falta incluir la cabecera <ciso646> (<iso646.h> en C).

Operadores de comparacin: ==, !=

Operadores con 1 argumento ( p g (usar argumentos con o g sin parntesis):


sizeof return delete

Operadores aritmticos: p
*, / (entre enteros se devuelve un entero) % (resto de la divisin)

Operadores de bit: &, ^, |, ~, <<, >> & ^ | ~ <<


14

Operadores
Operador de expresin condicional:
valor = (x<0) ? x : -x; (condicin entre parntesis)

Cada operador tiene definida una asociatividad (izquierdaderecha o derecha-izquierda). Ejemplo: a + b + 3 += += 3; equivale a a + += (b + += 3) 3); cout << a = <<a; equivale a (cout << a = ) << a; Para expresiones con varios operadores, C++ coloca parntesis de acuerdo a (ver tablas siguientes):
Prioridad entre operadores (decreciente verticalmente y equivalente horizontalmente) Asociatividad de operadores
15

Operadores
Prioridad (decreciente)

16

Operadores
Prioridad (decreciente)

17

Conversiones de tipo (i) p ()


Para tipos predefinidos Es aconsejable evitar castings explcitos son fuente de explcitos, errores. En C++ muchos castings son innecesarios en situaciones g donde s lo eran en C. Evitar los castings al estilo de C:
int i t x=3; 3 double y=3.4; x=y; x=(int)y;

// warning // no recomendado en C++

Notacin funcional: x=int(y); Para tipos predefinidos es equivalente a: x=(int)y; La notacin T() devuelve el valor por defecto para el tipo T: int j=int(); ( (til cuando se definen templates). f )
18

Conversiones de tipo (ii) p ( )


Para tipos predefinidos

Castings al estilo C++:


Operador static_cast: convierte entre dos tipos relacionados (ej.: punteros en la misma jerarqua de herencia, entero a enumerado, punto flotante a entero)
int x = 3; double y = 4.5; x = static_cast<int>(y); // x vale 4

Operador reinterpret_cast: convierte entre dos ti O d i t t t i t t d tipos sin i relacin: double* x = reinterpret_cast<double *>(3); Operador dynamic cast: conversin controlada en dynamic_cast: tiempo de ejecucin. Operador const cast: para quitar los calificadores const const_cast: 19 y volatile a punteros.

Instrucciones C++
Declaraciones.
Es aconsejable inicializar las variables a la vez que se declaran, para evitar llamar a constructores innecesariamente. Introducir l I t d i las variables en el menor bit posible. i bl l mbito ibl

Instrucciones de seleccin:
if (condition) statement if (condition) statement else statement switch (condition) statement ( ) Los operadores de comparacin: ==,!=,<,<=,>,>= devuelven bool(true) si la comparacin es verdadera y bool(false) si es falsa. Los L operadores l i d lgicos && || no evalan su segundo argumento a &&, l d t menos que sea necesario. Es posible declarar variables en condicionales: p if (double d=prim(true)) left/=d; 20

Instrucciones C++
Instrucciones de iteracin:
while (condition) statement do statement while (expression); for (for-init-statement conditionopt; expressionopt)

Se pueden declarar variables en el for:


void f(int v[], int max) { for (int i 0; i<max; i++) v[i] = i*i; i=0; i max; i ) i i; }

// el mbito de i es el bloque for

Goto: no usar!
goto identifier; identifier: statement
21

Constantes
Una variable tipo const necesita un valor inicial const Tipos primitivos no punteros:
const int x = 3; x=7; // error d compilacin 7 de il i

Objetos:
Observacin: const Punto p; es vlido (se considera que Punto p; p; est dando un valor inicial con constructor vaco) const Punto p1(3,4); Punto p2(5,6); p1 p2; p1=p2; //incorrecto; p1.x 33; // incorrecto p1.x=33;

Literales de caracteres:
char * p = casa; p[0] u ; p[0]=u; // error de ejecucin char cad [] = casa; cad[0]=u; // vlido porque cad es una copia del literal Si aparece casa varias veces, Visual C++ crea un solo hueco de 22 memoria para este literal, aunque es dependiente de la implementacin.

Constantes
Punteros:
Puntero constante:
long * const p = &numero; ( l (p= incorrecto, *p= ok) i t * k)

Puntero a constante:
const long * p = &numero; (*p= incorrecto, p= ok)

Array constante:
const int nums[3]={1,2,3}; (nums[1]= incorrecto)

Puntero a objeto constante: j


const Punto * p3=new Punto(3,4); (*p=, p->atributo=,incorrectos)

No permitido usar referencias no const a partir de elementos l t const: t


const int x=3; int & y = x; // incorrecto const Punto p1(3 4); Punto & p2 =p1; // incorrecto p1(3,4);
23

Gestin de Memoria
C: malloc free malloc, C++:
Variables
int * p1 = new int; // tipos primitivos Punto* p2 = new Punto (3,4); Punto* p3 = new Punto (); Punto* p4 = new Punto; // constructor vacio delete p1; delete p2;

Arrays:
int * p1=new int[3]; Punto * p2 = new Punto[3]; // constructor vaco delete [] p1; delete [] p2;

El uso de delete para memoria no dinmica produce un error de ejecucin Se debe usar delete o delete [] convenientemente delete delete [] (segn se aplique a un array o no)

24

Indice
Tipos y Declaraciones. p

Funciones.
Clases. Cl Espacios de Nombres. p Biblioteca Estndar (STL). Herencia. Herencia Manejo de Errores. Entrada/Salida.
25

Funciones
Una funcin no se puede llamar a no ser que se haya declarado previamente. La declaracin d una f L d l i de funcin h d especificar: su i ha de ifi nombre, el tipo devuelto, el nmero y tipo de sus argumentos. argumentos La semntica del paso de argumentos es igual a la de inicializacin. c a ac Una definicin es una declaracin donde se incluye el cuerpo de la funcin. p Las funciones han de definirse exactamente una vez.
26

Funciones
Definicin.

La definicin de L d fi i i d una f funcin puede ll i d llevar:


extern (disponible para otros archivos). Valor por defecto. defecto static (no disponible para otros archivos)

Sobrecarga: En C++ puede haber ms de una definicin para el mismo nombre de funcin (no en C). Observacin: El estilo antiguo de declaracin de funciones de C no es vlido en C++: C :
double media (datos, dim) ; g double * datos; long dim { }
27

Funciones
Argumentos.

Argumentos opcionales:
Argumentos = (, tipo variable = valor-defecto, ) Para evitar ambigedades, detrs de un argumento opcional no pueden i otros que no l sean d ir t lo

Nmero variable de argumentos (vlido tambin en C):


void dibujar ( x, int y, ) j (int , )
Llamadas posibles:
dibujar(3); dibujar(3,4); dib j (3 4 5) dibujar(3,4,5); // error // y={4} // y={4,5} {4 5}

La cabecera <cstdarg> (<stdarg.h> en C) contiene macros para acceder a los elementos de y (en el ejemplo anterior) Un ejemplo: printf printf Equivalente: void dibujar (int x, int y )

28

Ejemplo
Argumentos por defecto.
#include <iostream> using std::cout; using std::endl; double potencia (long base, long exponente = 2) { if (exponente == 2) return (base * base); else { double res = base; for (long i=1; i<exponente; i++) ( g ; p ; ) res *= base; return res; } } void main() { cout << "potencia (3) = " << potencia (3) << endl; cout << "potencia (3, 4) = " << potencia (3, 4) << endl; }

29

Funciones
Argumentos Variables.
#include <iostream> #include <cstdarg> void error (int severity ...) // "severity" seguido de una lista de char*s terminado en 0 { va_list ap; va_start(ap, severity); // inicializar arg for (;;) { char * p = va_arg(ap, char *); if (p == 0) break; std::cerr << p << " "; } va_end(ap); std::cerr<<"\n"; if (severity) exit(severity); } void main() { error(1, "error", "muy", "severo", 0); }

30

Funciones
Punteros a Funciones

Declaracin ( j D l i (ejemplo): l )
int (* funcion) (int x); int funcion) (i t ) i t (* f i ) (int );

Asignacin:
funcion=g; f i funcion=&g;

Llamada: Ll d
funcion(3); (*funcion)(3); (*f i )(3)
Cmo se declara un array de punteros a funciones?
int ( ** func ) (int) = new (int (*[7])(int)); int ( * func2 [4]) (int);
31

Funciones
Punteros a Funciones. Ejemplo. int h(int x) { ) return 4; } int g (int n, int (*f) (int)) { int u = f(3); // tambin vlido (*f)(3) return u; } int k=g(5, h); //tambin vlido g(5,&h);

32

Preprocesador
#define DIM 20 #define curva(a) 1+2*a+a*a Alternativa a funciones inline inline double curva (double a) { return 1+2*a+a*a ; }

Siempre es preferible el uso de funciones inline. Inclusin condicional:


#ifndef, #if, #else, #pragma once
33

Biblioteca Estndar de C
<assert.h> <assert h> (macro assert ) assert, ) <ctype.h> (comprobaciones de tipo) <errno.h> (errores de fuera de rango de nmeros, ) <float.h> (constantes para los nmeros reales: valor mximo del tipo double, ) <limits.h> (tamao de los enteros short, ) <locale.h> (adaptaciones al idioma) <math.h> (funciones matemtica:sin, cos, ) <setjmp.h> <setjmp h> (saltarse niveles de ejecucin) <stdarg.h> (acceso a los argumentos de una funcin con un numero variable de argumentos) <stddef.h> (tipos y macros tiles) <stdio.h> (funciones, tipos y macros para operaciones IO: printf, scanf, ) <stdlib.h>(funciones para conversin de nmeros y reserva dinmica de memoria: atof, atoi, _itoa, malloc, free,
)

<signal.h> (seales de interrupcin externa) <string.h> (strcmp, strcpy, strlen, ) g <time.h> Reemplazadas por <cnombre-cabecera> en C++ (ej.: <cstdio>, etc.), las funciones se hacen accesibles desde el espacio de nombres std:

#include <cstdio> using std::printf;

34

Indice
Tipos y Declaraciones. Funciones. F i

Clases.
Definicin. D fi i i Atributos e inicializacin. Encapsulamiento. Encapsulamiento Constantes. Tipos Internos. Internos Castings Espacios de Nombres Nombres. Biblioteca Estndar (STL). Herencia. Manejo de Errores. Entrada/Salida.

35

Clases
Definicin. Definicin de clase: class NombreClase { };
Debe acabar en ; (es obligatorio tambin en estructuras y en prototipos de mtodos dentro de la clase)

Para cualquier clase X se supone que existen por defecto las siguientes definiciones: Un constructor vaco
X::X() Llamada implcita al constructor vaco de clases padre y al constructor vaco para sus elementos que sean objetos Al sobrecargarlo, desaparece esta definicin por defecto

Un constructor especial (constructor de copia) que llama recursivamente al constructor de copia para sus elementos
X::X(const X &) ( ) Una llamada explcita al constructor de copia se puede poner como un 36 casting

Clases
Definicin.

Un destructor ( di vaco) U d t t (cdigo )


X::~X() Al destruir un objeto (para los casos de memoria automtica o en llamadas a delete para memoria dinmica), se llama al destructor del objeto y despus se destruyen las variables del objeto

El operador asignacin =, que p defecto p g q por llama al operador = para los elementos del objeto
X::operator=(const X & x) X t ( t ) X::operator=(const otroTipo & t) operator=(tipoPrimitivo, tipoPrimitivo) no es vlido p ( p , p )
37

Clases
Ejemplo definicin por defecto.
#include <iostream> class Rect { double x, y; public: double getX() const { return x; } double getY() const { return y; } Rect & setX( double d ) { x = d; return * this; } Rect & setY( double d ) { y = d; return * this; } }; void main() { // Ejemplo llamadas a elementos por defecto Rect r, r2; // llamada 2 constructores vacios r.setX(10).setY(20); Rect r1 = r; // llamada constructor copia r2 = r1; // operador asignacin // llamada tres destructores }

38

class Rect { static int max_data; Ejemplo definicin. definicin double x, y; x int * data; public: Rect(double cx = 0, double cy = 0) : x(cx), y( y) data(new int[max_data]) {} ( y ) ( ) y(cy), ( [ _ ]) Rect(const Rect & r ) : x (r.x), y(r.y), data(new int[max_data]) { for (int i = 0; i < max_data; i ++ ) data[i] = r.data[i]; } // el copiador por defecto hara this->data = r.data, cosa que no queremos ~Rect() { delete [] data; } Rect & operator= (Rect & r2 ) { x=r2.x; y y=r2.y; y setData(r2.getData()); return * this; } double getX() const { return x; } double getY() const { return y; } int * getData() { return data; } Rect & setX( double d ) { x = d; return * this; } Rect & setY( double d ) { y = d; return * this; } Rect & setData( int * d ) { for (int i = 0; i < max_data; i ++ ) data[i] = d[i]; return * this; } 39 }; int Rect::max_data = 10;

Clases

Clases
Atributos.

Se declaran mediante:
tipo variable; (sin dar un valor inicial)
La variable tomar un valor al llamar a un constructor de la clase, podemos tener los siguientes casos:
Llamada variable(valor) en la cabecera del constructor, que llamara al constructor correspondiente si l variable es un objeto ll l t t di t i la i bl bj t En caso contrario, si la variable es un objeto, se llamara al constructor vaco para tipo Si aparece this->variable=valor en el cdigo del constructor se producira tambin una llamada al operador = de tipo

tipo NombreClase::variable; tipo NombreClase::variable; Si es un atributo de clase se debe inicializar fuera de la clase, como si fuera una variable global. g
40

Clases
Atributos.

Pueden P d ser referenciadas en constructores o f i d t t mtodos mediante:


variable i bl this->variable NombreClase::variable para atributos d clase o N b Cl i bl t ib t de l resolucin de mbito (clases base que definen at buto con gua o b e) atributo co igual nombre).

Observacin: la siguiente instruccin es vlida


this->x=x; (si x es variable de objeto y tambin una variable local de un constructor o mtodo) )
41

#include <iostream> #include <string> using std::cout; using std::string;

Clases
Inicializacin Atributos Objetos. Ejemplo (i).

class Persona{ string nombre; int edad; public: Persona(string n="Fernando", int e=18) { nombre = n; edad = e; cout << "Constructor ;mostrar(); } void mostrar() { cout << "Persona::" << nombre << ", edad " << edad << "\n; } }; class Empresa { Persona jefe; string nombre; public: Empresa(Persona j, string n) { nombre = n; jefe = j; } void mostrar() { cout << "Empresa::" << nombre << "\n << "Jefe::"; jefe.mostrar(); jefe mostrar(); } Salida }; void main() { Persona p("Luis", 33); Empresa e(p, "Google"); e.mostrar(); }

Constructor Persona::Luis, edad 33 Constructor Persona::Fernando edad 18 Persona::Fernando, Empresa::Google 42 Jefe::Persona::Luis, edad 33

#include <iostream> #include <string> using std::cout; using std::string;

Clases
Inicializacin Atributos Objetos. Ejemplo (ii).

class Persona { string nombre; int edad; public: Persona(string n="Fernando", int e=18) : nombre(n), edad(e) { cout << "Constructor "; mostrar(); } void mostrar() { cout << "Persona::" << nombre << ", edad " << edad << "\n; } }; class Empresa { Persona jefe; string nombre; public: Empresa(Persona j, string n) : jefe(j), nombre(n) { } void mostrar() { cout << "Empresa::" << nombre << "\n << "Jefe::"; jefe.mostrar(); } }; void main() { Persona p("Luis", 33); Empresa e(p, "Google"); e.mostrar(); }

Salida
Constructor Persona::Luis, edad 33 C t t P L i d d Empresa::Google Jefe::Persona::Luis, edad 33
43

#include <iostream> using std::cout;

Clases
Atributos. Ejemplo (i).

Inicializacin class P { protected: int x; public: P(int a=0) : x(a) { cout << "Constructor "; show(); } void show() { cout << "P {x=" << this->x <<"}\n"; } }; class H : public P { int x; public: H(int b) : x(b), P(b+1) { P::x += this->x; cout << "Constructor H, {x=" << this->x <<"}\n"; show(); } }; void main() { H p(2); }

Salida Constructor P {x=3} Constructor H, { 2} C t t H {x=2} P {x=5}

44

#include <iostream> using std::cout;

Clases
Atributos. Ejemplo (ii).

Inicializacin class P { protected: int x; public: P(int a=0) : x(a) { cout << "Constructor "; show(); } void show() { cout << "P {x=" << this->x <<"}\n"; } }; class H : public P { int x; public: H(int b) : x(b) // se llama al constructor por defecto de P { P::x += this->x; cout << "Constructor H, {x=" << this->x <<"}\n"; show(); } }; void main() { H p(2); }

Salida Constructor P {x=0} Constructor H, {x=2} H P {x=2}

45

#include <iostream> using std::cout;

Clases
Atributos. Ejemplo (iii).

Inicializacin class P { protected: int x; public: P(int a=0) : x(a) { cout << "Constructor "; show(); } void show() { cout << "P {x=" << this->x <<"}\n"; } }; class H : public P { int x; public: H(int b) : x(b), P(x+1) { P::x += this->x; cout << "Constructor H, {x=" << this->x <<"}\n"; show(); } }; void main() { H p(2); }

Salida Constructor P {x=-858993459} Constructor H, { 2} C t t H {x=2} P {x=-858993457}

Primero se llama al constructor de la clase base!

46

#include <iostream> using std::cout;

Clases

class P Inicializacin Atributos. Ejemplo (iv). { protected: int x; public: P(int a=0) : x(a) { cout << "Constructor "; Salida show(); } Constructor P {x=3} void show() { cout << "P {x=" << this >x <<"}\n"; } P {x this->x << }\n ; Constructor H, { 858993460 y=2} C t t H {x=-858993460 2} }; P {x=-858993457} class H : public P { int x; int y; Los atributos se inicializan public: atendiendo al orden de su declaracin! H(int b) : y(b), x(y), P(b+1) { P::x += this->x; cout << "Constructor H, {x=" << this->x << y=<<y <<"}\n"; show(); (); } 47 }; void main() { H p(2); }

#include <iostream> using std::cout; class P Inicializacin { protected: int x, z; public: P(int a=0) : x(a), z(a+1) { cout << "Constructor "; show(); } void show() { cout << "P {x=" << this >x <<"}\n"; } P {x this->x << }\n ; }; class H : public P { int x; int y; public: H(int b) : y(b), x(y), z(b+1) // Error!! { P::x += this->x; cout << "Constructor H, {x=" << this->x << y=<<y <<"}\n"; show(); (); } }; void main() { H p(2); }

Clases
Atributos. Ejemplo (v).

48

Clases
Encapsulamiento.

Declaraciones public: private: protected:: public:, private:,


Pueden afectar a varias declaraciones Puede haber, por ejemplo, varios private: ( estilo de Java) j (al ) Por defecto es private: (en un struct, por defecto es public). Constructores y destructores suelen ser pblicos (a no ser q que no q queramos exponer un determinado constructor, ej.: el p , j de copia). protected: descrito ms adelante en herencia

Desde un constructor no se puede llamar a otro constructor de la misma clase (como en Java haciendo this( ))) aunque s a constructores de otras clases y this() )), de la clase padre.
49

Const
Variables const: V i bl t
Tipos primitivos y objetos
No se puede modificar su valor Otras operaciones no son posibles: por ejemplo, no se puede asignar mediante = a otra variable referencia del mismo tipo.
Por ejemplo, para const A a1;: A & a2=a1; incorrecto const A & a2=a1; correcto

Punteros y referencias: no se puede modificar el valor P t f i d difi l l referenciado


Para punteros, un const p p , puede hacer referencia a la variable puntero al colocar const junto a la variable
50

Const
Ejemplo
#include <iostream> using std::cout; class H { int x; public: bli H(int b) : x(b) { } void setX(int g) {x=g;} }; void main() { H p(2), j(4); (2) j(4) const H * h = &p; h = &j; h->setX(7); ( ); }

Es correcto?

// OK, es un puntero a una constante // error!


51

Const
Ejemplo
#include <iostream> using std::cout; class H { int x; public: bli H(int b) : x(b) { } void setX(int g) {x=g;} }; void main() { H p(2), j(4); (2) j(4) H * const h = &p; h = &j; h->setX(7); ( ); }

Es correcto?

// error! es puntero constante // ok


52

Const
Ejemplo
#include <iostream> using std::cout; class H { int x; public: bli H(int b) : x(b) { } void setX(int g) {x=g;} }; void main() { const H p(2), j(4); t (2) j(4) H * h = &p; h = &j; h->setX(7); ( ); }

Es correcto?

// error! es puntero a H no a const H

53

Const
Declaracin const dentro de cdigo de clases: g
Asignable a los tipos que aparecen en mtodos y constructores: argumentos y valor de retorno Al final del prototipo de un mtodo de objeto:
*this=, this->atributo=, incorrectos Ejemplo:
double Punto::distancia (const Punto & p) const {
return sqrt(p.x*x+ p.y*y); }

Atributos de objeto de tipo & y/o const


Deben de ser inicializados obligatoriamente en el constructor de la forma variable(valor) Si una variables es const entonces deja de estar definido el operador =
54

Const
Ejemplo
#include <iostream> using std::cout; class H { int x; public: H(int b) : x(b) { } ( ) ( ) void setX(int g) {x=g;} void mostrar() { cout << x; } }; void main() { H p(2), j(4); const H * h = &p; p; h = &j; h->mostrar(); }

Es correcto?

// error! es puntero a const H

55

Const
Ejemplo
#include <iostream> using std::cout; class H { int x; public: H(int b) : x(b) { } ( ) ( ) void setX(int g) {x=g;} void mostrar() const { cout << x; } }; void main() { H p(2), j(4); const H * h = &p; p; h = &j; h->mostrar(); }

Es correcto?

// OK, llamada a un mtodo const

56

Const
Ejemplo
#include <iostream> using std::cout; class H { const int x; public: H(int b) { x = b;} ( ) ;} void mostrar() const { cout << x; } }; void main() () { H p(2), j(4); const H * h = &p; h = &j; j; h->mostrar(); }

// error C2758: 'H::x' : must be initialized // in constructor base/member i iti li i t t b / b initializer li t list

Es correcto?

57

Const
Ejemplo
#include <iostream> using std::cout; class H { const int x; public: H(int b) : x(b) {} ( ) ( ) void mostrar() const { cout << x; } }; void main() () { H p(2), j(4); const H * h = &p; h = &j; j; h->mostrar(); }

Es correcto?

58

using std::cout; class H { int x; public: H(int b) : x(b) {} void mostrar() const { cout << x; } void setX(int in) { x = in; } }; class I { int y; public: I(int a=0) : y(a) {} void foo(const H & h) { h.mostrar(); h.setX(y); } void bar(H & h) { h.mostrar(); h.setX(y); } }; void main() { H p(2); const H & h = p; I i; ; i.foo(p); i.bar(h); }

Argumentos Const
Ejemplo

Es correcto? E t ?
// error C2662: 'H::setX' : cannot convert 'this' // pointer from 'const H' to 'H &'

// error C2664: 'I::bar' : cannot convert parameter 59 // 1 from 'const H' to 'H &'

Tipos Internos a Clases


Definiciones internas de clases:
Dentro de una clase se puede definir otra clase p (tambin estructuras, tipos mediante typedef, ). )
Se podran hacer llamadas internas al tipo definido o tambin a NombreClase::NuevaClase Tambin sera posible hacer llamadas externas a NombreClase::NuevaClase

No se pueden definir funciones dentro de mtodos.


60

Tipos Internos a Clases


Ejemplo clase interna
#include <iostream> using std::cout; class H { Salida int x; class in{ Constructor H {x=2 attr c=2} H, {x 2 attr.c 2} int c; public: in ( int d = 0 ) : c(d) {} int getc () { return c; } } attr; public: H(int b) : x(b), attr(b) { cout << "Constructor H, {x=" << x << " attr.c=" << attr.getc() << "}\n"; } }; void main() { H p(2); }
61

#include <iostream> using std::cout; class H { int x; public: class in{ int c; public: in ( int d = 0 ) : c(d) {} int getc () { return c; } } attr;

Tipos Internos a Clases


Ejemplo clase interna

H(int b) : x(b), attr(b) { cout << "Constructor H, {x=" << x << " attr.c=" << attr.getc() << "}\n"; } }; void main() { H p(2); (2) H::in b; }

62

Castings
Un casting equivale a una llamada a un constructor de un argumento. Ejemplo:
(Complejo)3 <---> Complejo(3) Complejo(c) <---> (Complejo)c
En donde c es otro complejo

Es muy recomendable evitar castings, y ms an al estilo C: (Complejo)c. C++ realiza castings implcitos. Ejemplo:
Complejo::Complejo(double x) : x(x), y( ) {} p j p j ( ) ( ) y(0) Complejo c1=3; Complejo c2(4); const Complejo& c3=5; // slo con tipos bsicos Complejo & c3=5; // incorrecto c3 5;
63

#include <iostream> using std::cout; class H { int x; public: H(int b) : x(b) {} void mostrar() const { cout << x; } void setX(int in) { x = in; } }; class I { int y; public: I(int a=0) : y(a) {} void foo(const H & h) { h.mostrar(); } void bar(H & h) { h.mostrar(); h mostrar(); h.setX(y); } }; void main(){ H p(2); const H & h = p; I i; i.foo(2); i.bar(2); }

Castings
Ejemplo

Es correcto? E t ?

64 // error C2664: 'I::bar' : cannot convert parameter // 1 from 'int' to 'H &'

#include <iostream> using std::cout; class H { int x; public: H(int b) : x(b) {} void mostrar() const { cout << x; } void setX(int in) { x = in; } }; class I { int y; public: I(int a=0) : y(a) {} void foo(const H & h) { h.mostrar(); } void bar(H h) { h.mostrar(); h mostrar(); h.setX(y); } }; void main(){ H p(2); const H & h = p; I i; i.foo(2); i.bar(2); }

Castings
Ejemplo

Es correcto? E t ?

65

Castings
Constructores explcitos

Declaracin explicit en un constructor, p j p deshabilita este procedimiento. Ejemplo:


explicit Complejo::Complejo(double)
Complejo c=4;, incorrecto Complejo c=4; Complejo c(4); correcto

Para una f P funcin como por ejemplo id g i j l void (Complejo c) la llamada g(3); es incorrecta La asignacin de valores a los argumentos de una funcin se hace mediante llamadas a constructor o constructor copia.

66

#include <iostream> using std::cout; class H { int x; public: bli explicit H(int b) : x(b) { cout << "Constructor H, {x=" << x << "}\n"; } H (const H & h) : x(h.x) { x = h.x; cout << "Constructor copia\n"; } H & operator = (int val) { x = val; cout << "asignacion\n"; g ; return * this; } }; void foo(H c) { cout << "foo\n"; } void main() { () H p(2); foo (2); }

Constructores Explcitos
Ejemplo

Es correcto?

No es correcto: error C2664: 'foo' : cannot convert parameter 1 from 'int' to 'H Equivalente a H c = 2;

67

Castings
Constructores explcitos

Para la clase class B { Complejo c; public: B(int x) : c(x) { } }; la llamada B b(3) es correcta
Las asignaciones de variables en constructores no utilizan a el g operador asignacin sino un constructor.

Complejo c=Complejo(4); correcto Complejo c=Complejo(4);


68

Castings
Constructores explcitos
Complejo & c(4); Complejo & c=4;
incorrectos (tanto con explicit o sin l)

const Complejo & c(4);, const Complejo & c=4; const c(4); const c=4;
correctos (caso no explicit); incorrectos (caso explicit)

Complejo & c=Complejo(4); , Complejo & c(Complejo(4)); Complejo c=Complejo(4); Complejo c(Complejo(4));
correctos (caso explicit o no explicit)

const Complejo & c=Complejo(4);, const Complejo & c(Complejo(4)); const c=Complejo(4); const c(Complejo(4));
correctos (caso explicit o no explicit)

Complejo c; c=4; , Complejo c=4;


correcto si no explicit y hay constructor por defecto, incorrecto si explicit, ya que se llama a Complejo::operator=(const Complejo &). Podra ser correcto si se ha definido Complejo & operator = ( p j p (double val) )

Java usa constructores explicit

69

Castings
Tipos
Problemas d uso d castings al estilo d C P bl de de ti l til de C: Difcil deteccin y errores imprecedibles en castings incorrectos Localizacin no trivial de castings en cdigo (parntesis con un tipo) Incoherencias con la conservacin de propiedades const al realizarlos En C++ se mantiene el uso de castings al estilo de C por compatibilidad con programas en C. En C++ aparecen otros castings: static_cast: convertir de un tipo a otro const_cast: eliminar propiedades d li i i d d de const y l til t volatile. dynamic_cast: para usar en sistemas jerrquicos de herencia reinterpret_cast: para realizar castings entre tipos no _ relacionados
70

Castings g
static_cast
static_cast <type-id> ( expression ) _

No es tan seguro como dynamic_cast, ya que no hace comprobaciones en tiempo de ejecucin. Normalmente para convertir de enumerados a enteros, o de punto flotante a enteros, o si se est seguro de los tipos de datos. dynamic_cast slo funciona con punteros o referencias, y el chequeo en tiempo de ejecucin supone una sobrecarga. Adems el down cast slo down cast funciona con tipos polimrficos.
// static_cast_Operator.cpp static cast Operator.cpp // compile with: /LD class B {}; class D : public B {}; void f(B* pb, D* pd) { D* pd2 = static_cast<D*>(pb); // downcastnot safe, pb may point to just B B* pb2 = static cast<B*>(pd); // upcast: always a safe conversion pb stat c_cast (pd); upcast a ays sa e co e s o }
71

Castings g
static_cast vs dynamic_cast
// static_cast_Operator_2.cpp // compile with: /LD /GR class B { public: virtual void Test(){} }; class D : public B {}; void f(B* pb) { D* pd1 = dynamic_cast<D*>(pb); D D* pd2 = static_cast<D >(pb); static cast<D*>(pb); }

Si pb apunta a un objeto de tipo D o a 0, pd1 y pd2 tendrn el mismo valor. valor Si pb apunta a un objeto de tipo B, dynamic_cast devuelve cero, mientras que static_cast devuelve un puntero de tipo D de manera t ti t incorrecta. 72

Castings g
dynamic_cast
dynamic_cast < type-id > ( expression )

type-id debe ser una clase definida anteriormente o un puntero a void. Slo funciona para tipos polimrficos. Si type-id es un puntero a una clase base accesible directa o indirectamente el type id indirectamente, resultado es un puntero al sub-objeto de tipo type-id.
// dynamic_cast_1.cpp // compile with: /c class B { }; class C : public B { }; class D : public C { }; void main () { D* pd = new D; C C* pc = dynamic_cast<C >(pd); // ok: C es una clase base directa dynamic cast<C*>(pd); // pc apunta al subobjeto de tipo C de pd B* pb = dynamic_cast<B*>(pd); // ok: B es una clase base indirecta // pb apunta al sub-objeto de tipo B subobject de pd }

Se llama upcast, y en realidad no hace falta casting.

73

Castings g
dynamic_cast
dynamic_cast < type-id > ( expression )

Si el tipo de expression es una clase base de type-id, se chequea en tiempo de ejecucin para ver si expression apunta realmente a un objeto completo de tipo type id type-id. Si es as, el resultado es un puntero a un objeto de tipo type-id:
// dynamic_cast_3.cpp dynamic cast 3 cpp // compile with: /c /GR class B {virtual void f();}; class D : public B {virtual void f();}; void main() { B* pb = new D; // ok B B* pb2 = new B; D* pd = dynamic_cast<D*>(pb); D* pd2 = dynamic_cast<D*>(pb2); } // ok: pb apunta a un D // pb2 apunta a un B no a un D, se devuelve 0
74

Se llama downcast y dynamic_cast necesita tipos polimrficos.

#include <iostream> using namespace std; class CCTest { public: CCTest(int a=0) : number(a) {} void setNumber( int num ) { number = num; } void printNumber() const; private: int number; }; void CCTest::printNumber() const { cout << "\nBefore: " << number; const_cast< CCTest * >( this )->number--; cout << "\nAfter: " << number; } int main() { CCTest X; X.setNumber( X setNumber( 8 ); X.printNumber(); const CCTest & Y = X; const_cast< const cast< CCTest &>(Y) setNumber(6); &>(Y).setNumber(6); const CCTest * Z = &X; const_cast< CCTest *>(Z)->setNumber(6); const_cast< const cast< CCTest &>(*Z) setNumber(6); &>( Z).setNumber(6); const CCTest U; const_cast< CCTest *>(&U)->setNumber(7); }

Castings g
const_cast

Salida Before: 8 After: 7

75

Atributos y Mtodos de Clase


Acceso:
Global:
NombreClase::variableOMetodo

En constructores y mtodos de objeto:


this->variableOMetodo variableOMetodo NombreClase::variableOMetodo

En mtodos de clase (static):


variableOMetodo NombreClase::variableOMetodo NombreClase::variableOMetodo

Inicializacin de los atributos de clase desde fuera de las clases (incluso siendo privados o protected). 76

#include "stdafx.h" #include <iostream> using namespace std; class Maze{ int x, y; public: Maze(int x, int y) : x(x), y(y) {} x x(x) }; class MazeFactory { public: static MazeFactory* Instance(); // existing interface goes here Maze * createMaze(int x, int y) { return new Maze(x, y); }; protected: MazeFactory() {}; private: static MazeFactory* _instance; }; MazeFactory* MazeFactory::_instance = 0; MazeFactory MazeFactory* MazeFactory::Instance () { if (_instance == 0) _instance = new MazeFactory; return _instance; } void main(){ Maze * m = MazeFactory::Instance()->createMaze(10,10); }

Ejemplo j p
singleton

77

Clases y Funciones Amigas


friend Clase; ; o friend funcionOMetodo [codigo] en una clase A supone: Acceso posible a parte private: de la clase A desde la clase, funcin o mtodo (NombreClase::nombreMetodo) amigos g
// classes_as_friends1.cpp // compile with: /c class B; class A { public: int Func1( B& b ); private: int Func2( B& b ); }; class B { private: int _b; // A::Func1 is a friend function to class B // so A::Func1 has access to all members of B friend int A::Func1( B& ); }; int A::Func1( B& b ) { return b._b; } // OK ( & O int A::Func2( B& b ) { return b._b; } // C2248 78

#include <iostream> using std::ostream; using std::cout;

Funciones Amigas

class Rect { static int max data; max_data; double x, y; int * data; public: Rect(double cx = 0, double cy = 0) : x(cx) y(cy) data(new int[max data]) { 0 x(cx), y(cy), int[max_data]) for (int i=0; i< max_data; i ++ ) data[i]=0; } ~Rect() { delete [] data; } friend ostream & operator << (ostream& os, const Rect & r); os }; int Rect::max_data = 10; ostream & operator << (ostream& os, const Rect & r) { os os << "Rect:{" << r.x << ", " << r.y << ", ["; for (int i=0; i< Rect::max_data-1; i ++ ) os << r.data[i] << " "; return os << r data[Rect::max data 1] << " ]}\n"; r.data[Rect::max_data-1] ]}\n ; }

void main() { Rect r(10,20); cout << r; }

79

Clases Amigas
// classes_as_friends2.cpp // compile with: /EHsc #include <iostream> using namespace std; class YourClass { friend class YourOtherClass; // Declare a friend class public: YourClass() : topSecret(0){} void printMember() { cout << topSecret << endl; } private: int topSecret; }; class YourOtherClass { public: void change( YourClass& yc, int x ){yc.topSecret = x;} }; int main() { YourClass yc1; YourOtherClass yoc1; yc1.printMember(); yc1 printMember(); yoc1.change( yc1, 5 ); yc1.printMember(); }

80

Clases y Funciones Amigas


La L amistad no es recproca a i d no ser que se especifique explcitamente:
class B { friend class A; ... }; class A { friend class B; ... }; class Base { friend class aFriend; f }; class Derived : public Base { }; amiga_de amiga de l Fi d class aFriend { friend class anotherFriend; }; class anotherFriend { }; } amiga_de

La amistad no se hereda (una subclase de A no puede acceder a miembros privados de B), ni es transitiva.

81

#include "stdafx.h" class Base { friend class aFriend; private: int x; public: Base(int n = 0 ) : x(n) {} ( ( ) }; class Derived : public Base { private: int y; public: Derived (int k = 3) : Base(k), y(k) {} }; class aFriend { friend class anotherFriend; p public: aFriend( Derived & d) { d.x = 9; d.y = 7; // error C2248 } }; class anotherFriend { public: anotherFriend( Base & b ) { b.x=0; } // // error C2248 th F i d( B b 0 };

Clases Amigas
Ejemplo

82

void main() { }

Indice
Tipos y Declaraciones. p Funciones. Clases. Clases

Espacios de Nombres. p
Ambito Biblioteca Estndar (STL) (STL). Herencia. Manejo de Errores. Entrada/Salida.
83

Ambito de variables variables.


Las variables se pueden definir en distintos mbitos anidados. La referencia a una variable se refiere al mbito ms cercano:
int x=7; void main(int argc, char* argv[]) { int x=8; { int x=9; ; cout << Valor: << x; // Valor:9 } }

Uso del operador de mbito ::

84

Espacios de Nombres (namespace)


Los L espacios d nombres son un i de b mecanismo para modularizar los programas. tiles sobre todo para programas grandes. Permite ag upa e e e tos (c ases, e te agrupar elementos (clases, funciones, variables, tipos, etc.) lgicamente relacionados. Un espacio de nombres define un mbito.
85

Espacios de Nombres
Posible anidamiento: el espacio de nombres puede ser:
espacioNombres1::espacioNombres2::espacioNombres3::

Por defecto est definido el espacio de nombres vaco (se incluyen la funcin main, y las variables, funciones y clases no asignados a ningn espacio de nombres) Las clases definen tambin un mbito (nombre de la clase). Los elementos de ese espacio de nombres son variables, mtodos, , clases, Se pueden definir espacios de nombres annimos. Llamadas posibles a elementos de un espacio de nombres mediante:
espacioNombres::elemento
86

Espacios de Nombres
Ejemplo
int b=11; namespace NS1 { int a=1; int b=2; namespace NS2 // NS2 anidado { int a=3; int b=4; void f() {} class A {}; } } int x=7; void main() { NS1::a=7; NS1::NS2::f(); ::x=34; } int b=11; namespace NS1 { int a=1; int b=2; namespace NS2 // NS2 anidado id d { int a=3; int b=4; void f() id f(); class A {}; } } void NS1::NS2::f() { std::cout << "f\n"; } int x=7; void main() { NS1::a=7; NS1::NS2::f(); NS1 NS2 f() ::x=34; }

87

Espacios de Nombres
Uso U en dif diferentes fi h t ficheros:
Fichero a.cpp:
namespace NS { p int x=3; void f () {}; }

Fichero b.cpp:
namespace NS { extern int x; void f (); // cabecera de la funcin int h = 4; // extender lo que hay en NS } ... main (...) { NS::x=7; NS::f(); NS f() ...

88

Espacios de Nombres
Espacios annimos
Sirven para ocultar nombres a otros ficheros ficheros. Proteccin contra colisiones de nombres. Los espacios de nombres annimos en distintos ficheros son distintos. No hay manera de acceder a un nombre de un espacio de nombres annimo de un fichero distinto.
#include header.h namespace { int i t a; equivale a void f() {/* */} void g() {/* */} }
#include header.h namespace $$$ { int a; void f() {/* */} void g() {/* */} } using namespace $$$ // $$$ es un nombre i i $$$; b nico
89

Espacios de Nombres
using namespace

Permite llamar a elementos de un espacio de nombres directamente sin poner explcitamente el espacio de nombres donde se encuentra Instruccin ejecutable en cualquier mbito (donde fuera aceptable, aceptable por ejemplo la instruccin int u=7;) ejemplo, int u 7; ) Sintaxis: using namespace espacioDeNombres; Esta declaracin se aplica por defecto para cualquier mbito para el espacio de nombres vaco y para los espacios de nombres annimos
90

Espacios de Nombres
Ejemplo
int i t a=10; 10 namespace NS1 { int a=1; int c=4; void f(){}; } namespace NS2 { int d=7; d 7; void f(){}; } namespace p { int b=3; } void main(int argc, char* argv[]) { using namespace NS2; using namespace std; int a=8; cout << "Valor:" << d; // Valor 7 f(); { using namespace NS1; cout << "Valor:" << a; Valor: // Valor // Al comentar la lnea // "int a=8;" se produce // un error de ambigedad g cout << "Valor:" << b; // Valor cout << "Valor:" << c; // Valor cout << "Valor:" << ::a; // Valor // f(); incorrecto por ambigedad } }

3 4 10

91

Espacios de Nombres
Uso de elementos
Sintaxis:
using espacioDeNombres::elemento;

Asigna en un determinado mbito una prioridad al uso de ese elemento:


Si el elemento declarado es una variable, no se puede definir en ese b to otra a ab e con e mbito ot a variable co el mismo nombre s o o be Si el elemento declarado es una funcin (f), no se puede hacer una llamada a otra declaracin using otroEspacioNombres::f; en el mismo mbito

Algoritmo
En un mbito determinado, al hacer una llamada a una variable, funcin o clase se mira en mbitos anidados las posibles definiciones clase, (incluyendo las declaraciones individuales de using) hasta el mbito ms global. En el mbito global se incluyen los elementos declarados mediante las declaraciones conjuntas de using que afectan a la llamada a la variable funcin o clase variable, clase.
92

Espacios de Nombres
Ejemplo
int a=10; namespace NS1 { int a=1; a 1; int c=4; void f(){}; } namespace NS2 { int d=7; void f(){}; } namespace { int b=3; }
void main(int argc, char* argv[]) { using std::cout; using NS1::a; // int a=8; es incorrecto using NS2::d; using NS1::f; // using NS2::f; incorrecto por ambigedad { using NS2::f; f(); // ejecucion de NS2::f() // si hubieramos hecho la declaracion // using namespace NS2;en lugar de la // declaracion using NS2::f; la ejecucion using NS2::f ;, // habria sido de NS1::f(); int d=37; cout << "Valor:" << a; // Valor 1 cout << "Valor:" << d; // Valor 37 cout << "Valor:" << NS2::d; // Valor 7 } }
93

Bsqueda de espacios de nombres


Es probable que una funcin que usa un tipo T se haya definido en el mismo espacio de nombres. Si una f funcin no se encuentra en el bit d su uso, i t l mbito de se busca en el mbito de sus argumentos.
namespace A { class B {}; void f (B & b) {}; }; void main() id i () { A::B b; f ( b ); }
94

Indice
Tipos y Declaraciones. Funciones. F i Clases. Espacios de Nombres. p

La Biblioteca Estndar (STL).


Introduccin. Plantillas. Contenedores. Iteradores. Algoritmos y Objetos Funcin. Adaptadores.
Herencia. Manejo de Errores. Errores Entrada/Salida.

95

La Biblioteca Estndar
Desarrollada por Stepanov A y Lee M de HP Stepanov, A. HP. Programacin genrica, uso extensivo de plantillas. Incluye: La biblioteca estndar d C L bibli t t d de Los contenedores (son templates)
<vector>, tabla unidimensional, <list>, lista doblemente enlazada, <set>, < t> conjunto, <map>, diccionario, < t i > cadena al estilo d j t < > di i i <string> d l til de C++

Entrada/Salida:
<iostream>, <iostream> que contiene cin cout y cerr cin, cerr. <iomanip>, para control del formato de salida. <sstream> y <strstream>, para flujos asociados a cadenas (al estilo de C++ y de C, respectivamente), <fstream>, flujos asociados con , p ), , j archivos

Otros:
<algorithm>, que contiene algoritmos generales como ordenacin,
96

La Biblioteca Estndar
Perteneciente al espacio d nombres td P t i t l i de b std La parte de la biblioteca estndar de C++ que contiene templates (clases o funciones), se llama Bibl t ll Bibloteca E t d d Pl till Estndar de Plantillas d C de C++ (STL, Standard Template Library)
<vector>, <string>, <algorithm>, < ector> <string> <algorithm>

Alguna referencia STL:


http://www.sgi.com/tech/stl/
97

La Biblioteca Estndar de C
Las bibliotecas estndares d C estn d fi id L bibli t t d de t definidas en la biblioteca estndar de C++ en el espacio de nombres std y en los ficheros cabecera: std
<cstdio>, <cmath>,

Por ejemplo, <cmath> es: ejemplo


namespace std { #include <cmath.h> }

Para usarla,
#include <cmath>; using namespace std; int p=abs(3);
98

Plantillas de Clase
Plantillas de mtodos y de clases:
Uso de class o typename como parmetros Se compilan sus instanciaciones

Plantillas de clases:
template <class T1, class T2, > class Clase {};
Incorrecto class Clase<T1 T2 > { }; Clase<T1,T2, > {};

Las plantillas de clases pueden tener:


Argumentos q sean tipos, constantes de tipos p g que p p primitivos (no valen punto flotante ni strings) o punteros. Ejemplo:
template <int x, int y, class T> class Matriz {};

Argumentos opcionales con valores por defecto (slo las plantillas de clase). Ejemplos:
template <int x, int y=1, class T=int> class Matriz {};
Matriz<3> m; Matriz 3

template <class T1, T2=vector<T1> > class UnaPlantilla {};

99

template <int x, int y, class T> class Matriz { T ** val; int dx, dy; public: bli Matriz () : dx(x), dy(y) { val = new T [dy][dx]; std::cout << "Def1"; for (int i = 0; i < dy; i ++) for (int j=0; j < dx; j ++ ) val[i][j] = 0; } // vlido tambin Matriz<x,y,T>() ( ); Matriz (int x); void f(); ~Matriz() {

Ejemplo

for (int i = 0; i < dy; i ++) delete [] val[i];


delete [] val; } };

Encuentra el Error

template <int x, int y, class T> Matriz<x,y,T>::Matriz(int x) : dx(x), dy(y) { // el parmetro x del constructor oculta el parmetro del template val = new T * [dy]; // val = new T [dy][dx]; no vale xq dx no es constante for (int i = 0; i < dy; i ++) val[i] = new T[dx]; for (int i = 0; i < dy; i ++) for (int j 0; j < dx; j ++ ) j=0; val[i][j] = 0; std::cout << "Def1"; } // incorrecto: Matriz::Matriz(int x) {}; template <int x, int y, class T> void Matriz<x,y,T>::f() {} void main() { Matriz<2,3,int> m(4); } // no se pueden usar variables no constantes como parmetros del template
100

template <int x, int y, class T> class Matriz { T * val[y]; int dx, dy; dx public: Matriz () : dx(x), dy(y) { for (int i = 0; i < dy; i ++) val[i] = new T [x]; std::cout << "Def1"; Def1 ; for (int i = 0; i < dy; i ++) for (int j=0; j < dx; j ++ ) val[i][j] = 0; } // vlido tambin Matriz<x y T>() Matriz<x,y,T>() Matriz (int x); void f(); ~Matriz() { for (int i = 0; i < dy; i ++) delete [] val[i]; } }; template <int x int y class T> Matriz<x y T>::Matriz(int x) : dx(x), dy(y) x, y, Matriz<x,y,T>::Matriz(int dx(x) { for (int i = 0; i < dy; i ++) val[i] = new T[dx]; for (int i = 0; i < dy; i ++) for (int j=0; j < dx; j ++ ) val[i][j] = 0; std::cout << "Def1"; } template <int x, int y, class T> void Matriz<x,y,T>::f() {} void main() { Matriz<2,3,int> m; }

Ejemplo

Ejemplo
Especializacin de Plantillas de clases
template <> class Matriz<2 3 int> { Matriz<2,3,int> public: Matriz<2,3,int> () {cout << Def2";} }; template <class T> class Matriz<2,3,T> { public: Matriz<2,3,T> () {cout << Def3";} }; template <class T> class Matriz<2,3,T*> { p public: Matriz<2,3,T*> () { , , {cout << Def4";} ;} }; /* C++ determina (mediante pattern matching) que: - Def2 es especializacin de Def3, Def1 - Def3 es especializacin de Def1 - Def4 es especializacin de Def1 */
102

Ejemplo
Especializacin de Plantillas de clases
void main() id i () { Matriz<3,4,int> m1; // Def:1 Definiciones posibles: 1 Matriz<2,3,int> m2; // Def:2 Definiciones posibles: 1 2 3 1,2,3. // Se elige, si existe, aquella que es // especializacin de todas las dems Matriz<2,3,char> m3; // Def:3 Definiciones posibles: 1,3 Matriz<2,3,char > Matriz<2 3 char*> m4; // Def:4 Definiciones posibles: 1,4 }
103

Ejemplo
Especializacin de Plantillas de funciones
template <class T1, class T2> void intercambia (T1 & t1, T2 & t2) { std::cout << "Def1"; } template <> void intercambia<int,int> (int & t1, int & t2) { std::cout << "Def2"; // excepcin: slo en una instanciacin completa se permite esta sintaxis } template <class T> void intercambia (vector<T> & t1, vector<T> & t2) { std::cout << "Def3"; } //El pattern matching utiliza toda la cabecera de la funcin, incluyendo args void main() { double d=3; int j = 7; intercambia(j, d); //Def1, def posibles: 1,2 intercambia(j, j); //Def2 intercambia(vector<int>(), vector<int>()); //Def3, def posibles: 1, 3 intercambia(vector<char>(), vector<int>());//Def1 }

104

Ejemplo
Especializacin de Plantillas de funciones
Observacin: si adems t Ob i i d tenemos l f la funcin: i void intercambia (int & t1, int & t2) { std::cout << "Def4"; } void main() { int x=3 y=5; x=3,y=5; intercambia(x,y); }

// Def:4 Defs posibles: 1,2,4

105

Templates
Un argumento de un template puede a su vez ser un template:
#include <iostream> template <class T> class c1 { public: T t; }; template <template<class A> class T> class c2 { public: T<int> atrib; }; int main() { c2<c1> myc2; myc2.atrib.t = 5; std::cout << myc2.atrib.t; } #include <iostream> iostream template <class T> class c1 { public: T t; t }; template <template<class A> class T, class R template class A R> class c2 { public: T<R> atrib; }; } int main() { c2 c1, int c2<c1, int> myc2; myc2.atrib.t = 5; std::cout << myc2.atrib.t; }

106

Templates
Typename
class Z { public: class U{}; }; template <class B> class A { typename B::U x; }; void main() { A<Z> a; }

107

Plantillas de mtodos
Similares a plantillas de funciones globales.
class X { public: template <class T> void f (); template <class T> void g (){} p (){}; }; template <class T> void X::f() { // X::f<T> //X::f<T> incorrecto } void main () { X x; x.f<int>(); // x f(); incorrecto porque no asigna valor a T x.f(); }

108

Plantillas de mtodos
template <int x, int y, class T> x y class Matriz { T ** val; int dx, dy; y public: Matriz () : dx(x), dy(y) { } Matriz (int x); template <class H> void f(); ~Matriz() { } }; template <int x, int y, class T> x y template <class H> void Matriz<x,y,T>::f() {}

109

Contenedores
Clases que almacenan objetos de algn (otro) tipo. Secuenciales: almacenan la coleccin de objetos del mismo tipo de manera lineal.
vector, list, deque.

Asociativos: proporcionan la capacidad de recuperacin rpida de informacin basada en claves.


Clave nica: set, map. Mltiples objetos con igual clave: multiset multimap multiset, multimap.
110

Vector
Conjunto de elementos en un orden lineal Acceso secuencial: uso de una clase iterator iterator Acceso aleatorio a elementos (uso de [ ]) Permite insercin y borrado. Eficiencia: Al final: O(1), En el medio: O(n) Principales operaciones: Constructores: vector::vector(), vector::vector(int), vector(const vector &) C t t t t () t t (i t) t ( t t vector::size(), vector::resize(int) Acceso (lectura/escritura) a primer, ltimo y cualesquiera elementos: T& vector<T>::front() const T& vector<T>::back() const T& vector<T>::operator[](vector::size_int) const En T& vector<T>::at (vector::size) const se lanzan excepciones en ( ) accesos errneos; menos eficiente que [] vector& vector::operator=(const vector&). Asignacin elemento a elemento bool operator==(const vector&, const vector&). Comparacin de elementos
111

Contenedores
Operaciones y Eficiencia

112

#include<vector> #include<iostream> using namespace std; int main() { vector<int> intV(10) // vector int de 10 elementos ecto <int> intV(10); ecto

Vector
Ejemplo (1) Ej l

for(int i = 0; i < intV.size(); intV[i] = i++); // acceso aleatorio // el vector se agranda intV.insert(intV.end(), 100 i i i 100); // aadir el numero 100 i for(int i = 0; i < intV.size(); cout << intV[i++] << endl); // use with an iterator for(vector<int>::iterator I = intV.begin(); I != intV.end(); ++I) cout << *I << endl; vector<int> newV(20); // all elements are 0 cout << " newV = "; for(int i = 0; i < newV.size(); cout << newV[i++] << " "); newV.swap(intV); cout << "\n newV after swapping = "; for(int i = 0; i < newV.size(); cout << newV[i++] << " "); cout << "\n\n intV = "; for(int i = 0; i < intV.size(); cout << intV[i++] << " "); }
113

Vector
Ejemplo (2)
vector<long> grupo(10); // 10 elementos // se inicializan con el const. X defecto. vector<short> u; // vector vaco vector<char> cesta (5, 'a'); // 5 elementos con valor a vector<char> otro(cesta); // copia; vector::vector(const vector &) vector<char>* cadena = new vector<char>(25); vector<char>::size_type s = cesta.size(); // s tiene valor 5 cesta.resize(3); // el vector pasa a tener 3 elementos vector<long> x(3, 7); // el vector es {7,7,7} vector<long>::iterator p; for (p=x.begin(); p!=x.end(); p++) { *p=8; // "vector::iterator vector::begin()", // vector::end(), iterator::operator++, // iterator::operator*, operator!= } x[0]=9; // el vector pasa a ser {9,8,8}; // "T & vector<T>::operator[](vector<T>::size_type)" p--; x.insert(p, 2); // el vector se convierte en {9,8,2,8} x.erase(x.begin()+1); // el vector acaba siendo {9,2,8}

114

Vector
Ejemplo
GUI para una estacin elctrica: t i l t i
Shape
gui_shapes

GUI_PE

#include <iostream> #include <vector> using std::vector; class Shape { /**/};

Turbine

Pipe

Switch

Horn
class Turbine : public Shape { /**/}; //

Electrical Switch

Mecanical Switch

class GUI_PE { vector <shape> gui_shapes; public: GUI_PE() : gui_shapes() {} GUI_PE & addShape( Shape & s) { gui_shapes.push_back(s); gui shapes push back(s); } };

115

Vector
Insercin/Reemplazo de elementos.
#include <iostream> #include <vector> using namespace std; void main() { vector<short> u; // vector vaco u.push_back(4); u push back(4); u.push_back(3); try { u.at(2)=4; } catch (out_of_range r) { std::cerr << r.what( ) << endl; std::cerr << "Tipo: " << typeid( r ) name( ) << endl; Tipo: ).name( } u[2] = 3; // error en tiempo de ejecucin }

Si la las operaciones de lista (insert, erase, push_back) son frecuentes, es mejor usar una lista.

116

Vector
Miembros
assign : Borra un vector y copia los elementos especificados al vector vaco vaco. at: Devuelve una referencia al elemento en la posicin especificada. back: Devuelve una referencia al ltimo elemento del vector. begin: Devuelve un iterador de acceso aleatorio al primer elemento del contenedor. capacity: Devuelve el n de elementos que el vector podra contener sin reservar ms memoria. clear: Borra los elementos del vector. empty: Comprueba si el vector est vacio. end: Devuelve un iterador de acceso aleatorio al ltimo elemento ms uno del contenedor. erase: Borra un elemento o un rango de elementos en un vector en posiciones especicadas. front: Devuelve una referencia al primer elemento del vector. get_allocator: Devuelve un objeto de la clase allocator usada por el vector. insert: Inserta un elemento o grupo de elementos en el vector en una cierta posicin posicin. max_size: Devuelve la longitud mxima del vector. pop_back: Borra el elemento final del vector. push_back: Aade un elemento al final del vector. rbegin: Devuelve un iterador al primer elemento en el vector inverso. rend: Devuelve un iterador al final del vector inverso. resize: Especifica un nuevo tamao para el vector. reserve: Reserva una longitud mnima de almacenamiento para el vector. size: Devuelve el nmero de elementos del vector. swap: Intercambia los elementos de dos vectores. operator[]: Devuleve una referenca al elemento del vector en cierta posicin.
117

La interfaz de los contenedores


Tipo de Datos
X::value_type yp X::reference X::const_reference X const reference X::iterator X::const_iterator X t it t X::difference_type X::size_type T Tipo de la referencia a los elementos del contenedor Idem para solo lect ra lectura Tipo del iterador Tipo del iterador Ti d l it d constante t t Tipo entero con signo para distancia entre elementos (diferencia entre dos punteros) Tipo entero sin signo para especificaciones de tamao.

Significado

La interfaz de los contenedores


Mtodos. Contenedores.
Mtodo
X() X(const X&) ~X() iterator begin() const_iterator begin() iterator end() const_iterator end() size_type max_size() size_type size() bool empty() void swap(X&) X& operator=(const X&) bool operator==(const X&) bool operator!=(const X&) bool operator<(const X&) bool operator>(const X&) bool operator<=(const X&) bool operator>=(const X&) Constructor copia. Destructor, llama al destructor de cada elemento del contenedor Principio del contenedor Principio del contenedor Posicin despus del ltimo elemento idem Tamo mximo posible del contenedor Tamao actual del contenedor size() == 0, o bien begin() == end() Intercambia elementos con el contenedor argumento.

Significado
Constructor por defecto, crea un contenedor vaco.

La interfaz de los contenedores


Contenedores Reversibles.
Se pueden recorrer de atrs hacia delante. p
X::reverse_iterator X::const_reverse_iterator rbegin() // points to last element b i () i t t l t l t rend() // points to fictitious position before the first element
vector<string> stringVec(4); t < t i > t i V (4) stringVec[0] = "First"; stringVec[1] = "Second"; stringVec[2] = "Third"; stringVec[3] = "Fourth"; stringVec.insert(stringVec.end(), string("Last")); //incremento de tamao cout << "size() = " << stringVec.size() << endl; // 5 vector<string>::iterator I = stringVec.begin(); ++I; // 2nd position stringVec.erase(I); stringVec erase(I); // delete Second cout << "size() = " << stringVec.size() << endl; // 4 for(I = stringVec.begin(); I != stringVec.end(); ++I) cout << *I << endl; for(vector<string>::reverse_iterator revI = stringVec.rbegin(); revI != stringVec.rend(); ++revI) cout << *revI << endl;

Clase string
Un U vector d h con otras f t de char t funcionalidades: i lid d reemplazar, etc:
typedef basic string<char char traits<char> allocator<char> > string; basic_string<char, char_traits<char>,

Operadores [], at, == similares a vector string::append aade un string al final Operadores + y += (concatenacin de cadenas) Operador << (salida de datos) Conversin a char*: string::c_str()
El destructor de string elimina la cadena de caracteres
121

Clase string
Ejemplo
#include <iostream> #include <string> using std::string; using std::cout; ( g , g []) void main(int argc, char* argv[]) { string cad1; // cadena vaca string cad2 (3, 'a'); // el string aaa string str1="012"; string str2("345"); const char * p= str1.c_str(); // "const char* string::c_str() const" cout << "Valor:" << p; // Valor:012 str1.append(str2); // "string & std::string::append(string&)" cout << "Valor:" << str1; // Valor:012345 // "ostream & operator<<(ostream &, string &)" }

122

Clase string
Ejemplo
const char * q; { string s="abc"; q=s.c_str(); q=s c str(); cout << "Valor:" << q; // Valor:abc } cout << "Valor:" << q << std::endl; // Valor: ... (algo sin sentido), ya que // s se elimina al salir del bloque q

123

Map
Conjunto de pares clave-valor. Dos pares p (mediante no pueden tener la misma clave ( operador ==).
Es conjunto ordenado (se puede recorrer el conjunto de pares mediante un it d ) segn j t d di t iterador) los valores de clave

124

Map
Ejemplo
map<string, map<string string> agenda; agenda["Elena"] = "91-2837363"; agenda["Fernando"] = "965-243396"; agenda[ Ruth ] agenda["Ruth"] = "95-2363204"; 95 2363204 ; agenda["Carlos"] = "91-4807303"; cout << agenda["Ruth"] << endl; agenda.erase (agenda.find ("Fernando")); ( Fernando )); map<string, string>::iterator z; for (z=agenda.begin(); z!=agenda.end(); z++) { cout << "[" << z->first << "," [ , << z->second << "]" << endl; } // Valores para Carlos, Elena y Ruth // (por orden alfabtico) // pair<T1, T2> est definida en <utility>

125

Map
Ejemplo
map<string, string,greater<string>> agenda; agenda["Elena"] = "91-2837363"; agenda["Fernando"] = "965 243396" d ["F d "] "965-243396"; agenda["Ruth"] = "95-2363204"; agenda["Carlos"] = "91-4807303"; cout << agenda["Ruth"] << endl; g [ ] agenda.erase (agenda.find ("Fernando")); map<string, string, greater<string>>::iterator z; for (z=agenda.begin(); z!=agenda.end(); z++) { cout << "[" << z->first << " " t >fi t "," << z->second << "]" << endl; } // Valores para Carlos, Elena y Ruth map<string, string, greater<string>>::reverse_iterator g; for (g=agenda.rbegin(); g!=agenda.rend(); g++) { cout << "[" << g->first << "," << g->second << "]" << endl; }
126

#include <iostream> #include <map> #include <string> using namespace std; typedef map<string, int> Tabla; void readitems (Tabla & m) { string word; int val = 0; while (cin >> word >> val) m[word] += val; } void main() { Tabla tbl; readitems (tbl);

Map
Ejemplo

Consola PCs 12 discos 10 PCs 12 fin fin PCs 24 discos 10 -----------------------------total 34

int total = 0; typedef Tabla::const iterator CI; Tabla::const_iterator for (CI p=tbl.begin(); p!=tbl.end(); ++p) { total += p->second; cout << p->first << '\t' << p->second << '\n'; \t \n ; } cout << "------------------------------\ntotal\t" << total << '\n'; }

127

#include<map> #include<string> #include<iostream> using namespace std; // two typedefs for abbreviations Ejemplo // comparison object: less<long>() typedef std::map<long, std::string> MapType; typedef MapType::value_type ValuePair; i int main() { MapType Map; Map.insert(ValuePair(836361136, "Andrew")); Map.insert(ValuePair(274635328, "Berni")); Map.insert(ValuePair(260736622, "John")); Map.insert(ValuePair(720002287, "Karen")); Map.insert(ValuePair(138373498, Thomas )); Map insert(ValuePair(138373498 "Thomas")); Map.insert(ValuePair(135353630, "William")); // insertion of John is not executed, because the key already exists. Map.insert(ValuePair(720002287, "John")); std::cout << "Output:\n"; MapType::const_iterator iter = Map.begin(); while(iter != Map.end()) { std::cout << (*iter).first << ':' << (*iter).second<< std::endl; ++iter; } long Number; std::cin >> Number; if((iter = Map.find(Number))!= Map.end()) std::cout << (*iter).second; else std:: cout << "Not found!"; }

Map

Otros Contenedores STL


set t
Conjunto ordenado (segn <) de elementos sin repeticiones. repeticiones

multiset.
Conjunto con repeticin repeticin.

hash_set
Un diccionario ordenado con uso de hashing hashing

list
Una lista doblemente enlazada

...
129

Iteradores
Generalizacin d puntero a un elemento d una secuencia: G li i de l de i Dereferencia (* y ->). Apuntar al prximo elemento (++). ( ). Comparacin (==, !=). Toda plantilla de funcin que toma un iterador como parmetro funciona con un puntero. int * es un iterador para un int[ ], list<int>::iterator es un iterador para un list<int>. Cabecera <iterator>, en namespace std.
130

Iteradores
begin() end()

elem[0]

elem[1]

elem[2]

elem[n 1] elem[n-1]

Tipos: input, output, forward, bidirectional, random-access

Cada contenedor devuelve un iterador (cont_type::iterator cont.begin()):


vector: iterador de acceso aleatorio. list: bidireccional.
131

Iteradores
Ejemplo input y output iterator
#include <iostream> #include <algorithm> #include <fstream> #include <string> using namespace std; int main( ) { ifstream ifile("words txt"); ifile( words.txt ); istream_iterator<string> is(ifile), eof; ostream_iterator<string> os(cout, "\n"); while (is!=eof) { *os++ = *is++; } // equivalente a: // copy ( istream_iterator<string>(ifile), // istream_iterator<string>(), istream iterator<string>() // ostream_iterator<string>(cout, "\n")); // tambin equivalente a: // string s; // while ( f >> s) cout << s << "\n"; (ifile ) \ ifile.close(); } words.txt esto es una frase salida esto es una frase

132

#include <iostream> #include <iterator> #include <vector> #include <list> using namespace std;

Ejemplo
Iteradores como parmetros

template< class it > void function( it i1, it i2 ) { cout << typeid(iterator_traits<it>::iterator_category).name( ) << endl; yp ( g y) ( ; while ( i1 != i2 ) { iterator_traits<it>::value_type x; x = *i1; cout << x << " "; i1++; salida }; struct std::random_access_iterator_tag cout << endl; ; aaaaaaaaaa }; struct std::bidirectional_iterator_tag 0000000000 int main( ) { struct std::random access iterator tag std::random_access_iterator_tag vector<char> vc( 10 'a' ); 10,'a' 123456789 list<int> li( 10 ); double v[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; function( vc.begin( ), vc.end( ) ) ( g () ( ); function( li.begin( ), li.end( ) ); function( v, v+10); }

133

Ejercicio
Del examen de Febrero 2008
(20 puntos): El mtodo main siguiente (cuyo resultado se main muestra ms abajo) utiliza un iterador secuencial (posiciones 1, 2, 3, etc) de un vector. Completar el programa para que sea vlido g (no {4,5,6} en un caso general ( slo int y no slo los valores { , , } en las posiciones {1,2,3}):
void main() { vector<int> v; v.push_back(4); v.push_back(5); v.push_back(5); Iterador<int> q1(&v); q1.imprime(); for (; !q1.finalizado(); ++q1) *q1=8; q1.imprime(); Iterador<int> & q2=++q1; q2.imprime(); } // SALIDA EN PANTALLA: Iterador:posicion=0,vector= 4 5 Iterador:posicion=3,vector= 8 8 Iterador:posicion=4,vector= 8 8

6 8 8

Ejercicio je c c o
Solucin
template <class T> class Iterador { private: vector<T> * v; int posicion; public: Iterador(vector<T> * v) : v(v), posicion(0) {} bool finalizado () { return posicion==v->size();} Iterador<T> operator ++() { posicion++; return *this; } T & operator * () { return (*v)[posicion];} void imprime () { cout << "Iterador:posicion=" << posicion << ",vector="; for (vector<T>::size_type i=0; i < v->size(); cout << "\t" << (*v)[i++] ); cout << endl; } };

Ejercicio
Modificar la clase Iterador<X> para q p que tambin funcione con arrays, de cualquier tipo.
void main () { int con[3] = {1, 2, 4}; Iterador<int> x(&con[0], &con[3]); x.imprime(); for (; !x.finalizado(); ++x) *x=8; x.imprime(); vector<char> vc; vc.push_back('a'); vc.push_back( b ); vc.push back('b'); vc.push_back('c'); Iterador<char> y(vc.begin(), vc.end()); y.imprime(); for ( ! fi li d () ++y) * 'd' f (; !y.finalizado(); ) *y='d'; y.imprime(); }

Solucin
template<class Elemento> class Iterador { vector<Elemento> v; int posicion; __w64 int max; public: template <class T> Iterador (T first, T last) : v(first, last), posicion(0),max(last-first) {}; bool finalizado () { return posicion==max;} p () Iterador<Elemento> operator ++() { posicion++; return *this; } Elemento & operator * () { return v[posicion];} void imprime () { cout << "Iterador:posicion=" << posicion << ",vector="; for (int i=0; i < max; cout << "\t" << v[i++] ); cout << endl; } };

Algoritmos de la STL
Cuatro C t grupos:
Operaciones secuenciales constantes (no cambian el orden de la secuencia). )
for_each, find, find_if, adjacent_find,

Operaciones secuenciales cambiadoras (pueden cambiar el orden de la secuencia) secuencia).


transform, copy, swap, replace, fill, reverse,

Operaciones de ordenacin y relacionadas.


sort, lower_bound, upper_bound, merge,

Operaciones numricas generalizadas.


accumulate, count, count_if, count if,

Es necesaria la cabecera <algorithm> g


138

Algoritmos de la STL
Ejemplo for_each
#include <iostream> #include <vector> #include <algorithm> using namespace std; void f (int x) {std::cout << x;} void main() { vector<int> numeros; int nums[3]={3,5,1}; numeros.push_back(3); numeros.push_bac ( ); u e os.pus back(1); numeros.push_back(2); sort(numeros.begin(), numeros.end()); for_each(numeros.begin(), numeros.end(), f); ( g (), (), ); for_each(nums, nums+3, f); // EJECUCIONES EQUIVALENTES sort<vector<int>::iterator> (numeros.begin(), numeros.end()); ( g (), ()); for_each<vector<int>::iterator> (numeros.begin(), numeros.end(), f); for_each<int*>(nums, nums+3, f); }

139

#include <iostream> #include <vector> #include <algorithm> using namespace std;

Algoritmos de la STL
Ejemplos (plantilla)

template<class In, class Op> Op & ff_e(In first, In last Op & f) { // similar a for each ff e(In first last, for_each while (first != last) f(*first++); return f; }; class objFun { int acum; public: objFun(int init=0) : acum(init) {} void operator() (const int & c) { acum += c; } void print() const { cout << acum << "\n"; } }; void f(int e) {cout << e << " ";} void main() { vector<int> v(6, 7); objFun ob; ff_e(v.begin(), v.end(), ob); ob.print(); ob print(); int b [6] = {1, 2, 3, 4, 5, 6}; ff_e(b, b+5, f); }

140

#include "stdafx.h" #include <iostream> #include <algorithm> #include <deque> # using std::ostream;

Algoritmos y Objetos Funcin

template <class T> class sum_up l { public: void operator() (const T & value ) { sum += value; } friend t f i d ostream & operator << (ostream & os, sum_up<T> s); t ( t T ) private: static T sum; }; int sum_up<int>::sum = 0; inline ostream & operator << (ostream & os, sum_up<int> s) { return os << s.sum; t }

salida
void main() { using std::deque; i td d using std::cout; deque<int> d(3, 2); sum_up<int> s; i t for_each (d.begin(), d.end(), s); cout << s; }

141

#include <iostream> #include <algorithm> #include <vector> using std::ostream;

Ejemplo find_if find if

template <class T> class find_first_greater { public: find_first_greater(const T & xx=0) : x(xx) {} bool operator() (const T & value ) { return value > x; } private: T x; }; void main() { using std::vector; using std::cout;

salida 4

vector<int> v(5); for (int i=0; i < 5; v[i++]=i); //v[] = {1, 2, 3, 4, 5} vector<int>::iterator i = fi d if (v.begin(), v.end(), fi d fi i i it find_if ( b i () d() find_first_greater<int>(3)); i (3)) it != v.end() ? cout << *it : cout << "not found"; }

142

Ejemplo sort
#include <iostream> #include <algorithm> #include <vector> inline bool greater ( int a, int b ) { return a > b; } void main() { using std::vector; using std::cout; i td t

salida 54321

vector<int> v(5); for (int i 0; i < 5; v[i++] i); // v[] = {1 2 3 4 5} i=0; v[i++]=i); {1, 2, 3, 4, sort(v.begin(), v.end(), greater); // v[] = {5, 4, 3, 2, 1} typedef vector<int>::const_iterator VCI; for (VCI first = v.begin(); first != v end(); cout << *first++); v begin(); v.end(); first++); }
143

Ejemplo sort
#include <iostream> #include <algorithm> #include <functional> #include <vector> using namespace std; void main() {

salida 54321

vector<int> v(5); i=0; v[i++]=i); for (int i 0; i < 5; v[i ] i); // v[] = {1, 2, 3, 4, 5} sort(v.begin(), v.end(), greater<int>()); // v[] = {5, 4, 3, 2, 1} typedef vector<int>::const_iterator VCI; for (VCI first = v.begin(); first != v.end(); cout << *first++); ( g () () ) }
144

#include <iostream> #include <numeric> #include <functional> #include #i l d <vector> #include <iterator> #include <string> using namespace std;

Ejemplo de accumulate
salida
1 0.5 0.333333 0.25 0.2 0.166667 0.142857 0.125 0.111111 0.1 The sum of 1 + 1/2 + 1/3 + ... + 1/10 is 2.92897 The product of 1 * 1/2 * 1/3 * ... * 1/10 is 2.75573e-007 The concatenated vector of strings: This is one sentence.

int main () { vector <float> rgFA(10); ostream_iterator <float> OstreamIt(cout," ");

// Initialize the array to 1,1/2,1/3,... for (int i=0; i<10; rgFA[i++]=(1.0f/i) ); // Print the array copy(rgFA.begin(),rgFA.end(),OstreamIt); cout << endl; // Sum the array cout << "The sum of 1 + 1/2 + 1/3 + ... + 1/10 is "<< accumulate(rgFA.begin(),rgFA.end(),0.0f)<< endl;

// Compute the product of the array cout << "The product of 1 * 1/2 * 1/3 * ... * 1/10 is "<< accumulate(rgFA.begin(),rgFA.end(),1.0f,multiplies<float>())<< endl; // Initialize array of strings g g ; vector<string> rgs; rgs.push_back("This "); rgs.push_back("is "); rgs.push_back("one "); rgs.push_back("sentence. "); // Concatenate the strings in the array and print the sentence cout << "The concatenated vector of strings: "<< accumulate(rgs.begin(),rgs.end(),string(""))<< endl; }
145

#include <iostream> #include <algorithm> #include f #i l d <functional> ti l #include <string> #include <vector> using namespace std;

Ejemplo count_if count if


salida She Sells Sea Shells by the Sea Shore Number of elements that start with letter "S" = 6

// Return true if string str starts with letter 'S' int MatchFirstChar( const string& str) {return str[0] == 'S';} S ;} int main(){ vector<string> NamesVect(8) ; //vector containing names NamesVect[0] = "She" ; NamesVect[1] = "Sells" ; NamesVect[2] = "Sea" ; NamesVect[3] = "Shells" ; N V t[3] "Sh ll " NamesVect[4] = "by" ; NamesVect[5] = "the" ; NamesVect[6] = "Sea" ; NamesVect[7] = "Shore" ; for(vector<string>::iterator it = NamesVect.begin(); it != NamesVect.end(); cout << *it++ << " "); cout << endl ; ptrdiff_t result = count_if(NamesVect.begin(), NamesVect.end(), MatchFirstChar) ; 146 cout << "Number of elements that start with letter \"S\" = " << int(result) << endl ; }

#include <iostream> #include <fstream> #include <vector> #include <string> #include <algorithm> g using namespace std;

Ejemplo Completo
dict.txt esto es un diccionario words.txt esto es una f frase

salida template <class bid_it, class T> una class nonAssocFinder { frase bid_it _begin, _end; public: nonAssocFinder(bid_it begin, bid_it end) : _begin(begin), _end(end) {} bool operator() ( p () (const T & word) { return binary_search(_begin, _ ) y_ (_ g _end, word); } ) };
void main() { // imprime todas las palabras de "words.txt" que no estan en "dict.txt ifstream dictFile("dict.txt"), wordsFile("words.txt"); ( ) ( ) vector<string> dictionary; // carga el fichero en el diccionario copy ( py (istream_iterator<string>(dictFile), istream_iterator<string>(), back_inserter(dictionary)); _ g ( ) _ g () _ ( y)) sort (dictionary.begin(), dictionary.end()); // ordena el diccionario remove_copy_if ( istream_iterator<string>(wordsFile), istream_iterator<string>(), g () ostream_iterator<string>(cout, "\n"), nonAssocFinder<vector<string>::iterator, vector<string>::value_type> (dictionary.begin(), dictionary.end()));

147

Adaptadores
Clases que se basan en otras para implementar nueva funcionalidad. Adaptadores de Contenedores: stack, queue, priority_queue.
#include <iostream> #include <stack> #include <vector> #include <list> #include <deque> #include <queue> using namespace std;

salida 10 6 5 3 1

void main() { stack<int,vector<int> stack<int vector<int> > s1; stack<int,list<int> > s2; stack<int,deque<int> > s3; s1.push(1); s1.push(5); s1.push(3); s1.push(10); s1.push(6); priority_queue<int, vector<int> priority queue<int vector<int>, less<int> > pq2(s1 c begin() s1 c end()); pq2(s1.c.begin(), s1.c.end()); while (!pq2.empty()) { cout << pq2 top() << "\n"; pq2.top() \n ; pq2.pop(); } }

148

Adaptadores
De iteradores: inversos (reverse_bidirectional_iterator), de insercin ( ), (back_insert_iterator, front_insert_iterator, insert_iterator)
salida lid
#include <iterator> #include <algorithm> #include <vector> #include i t #i l d <iostream> int main( ) { using std::vector; using std::cout; 1 2 3 4 5 El vector al reves es: 5 4 3 2 1 iterator pos = 4 reverse_iterator rpos = 3

vector<int> vec; for ( int i = 1 ; i < 6 ; vec.push_back ( i++ ) ); for ( vector <int>::iterator vIter = vec.begin ( ) ; vIter != vec.end ( ); cout << *vIter++ << " " ); cout << "El vector al reves es: "; for ( vector <int>::reverse_iterator rvIter = vec.rbegin( ) ; rvIter != vec.rend( ); cout << *rvIter++ << " "); vector <int>::iterator pos = find ( vec.begin ( ), vec.end ( ), 4 ); cout << "iterator pos = " << *pos << "\n"; t "it t * "\ " vector <int>::reverse_iterator rpos ( pos ); 149 cout << "reverse_iterator rpos = " << *rpos << "\n"; }

Adaptadores
De funciones: negadores (neg1 y neg2), binders (bind1st, bind2nd), de punteros a funciones.
#include <functional> #include <algorithm> g #include <vector> #include <iostream> using namespace std; i td int main( ) { vector<int> vec; for ( int i = 5 ; i >= 0 ; vec.push_back ( i-- ) ); sort(vec.begin(), vec.end(), not2(greater<int>())); for ( int i = 0 ; i < 6 ; cout << vec[i++] << " " ); co t ec[i++] ) }

salida 012345

150

Ejercicio
Utilizando la STL realiza un programa que lea un fichero STL, con nmeros enteros e imprima por pantalla en orden descendente aquellos mayores de 10.
#include <iostream> #include <fstream> #include <vector> #include <algorithm> #include <functional> using namespace std; inline bool lesseq10(int a ) {return a<=10; } void main() { // imprime todas los numeros > 10 ifstream numsFile("numbers.txt"); vector<int> nums; remove_copy_if (istream_iterator<int>(numsFile), istream_iterator<int>(), back_inserter(nums), lesseq10); sort (nums.begin(), nums.end(), greater<int>()); // ordena el diccionario copy (nums.begin(), nums.end(), ostream_iterator<int>(cout,"\n")); }

Indice
Tipos y Declaraciones. Funciones. Funciones Clases. Espacios de Nombres. Biblioteca Estndar (STL).

Herencia.
Control de A C t l d Acceso. Polimorfismo. Herencia y Templates. p Punteros a Miembros de Clase. Castings y RTTI. Ambigedad. A bi d d Operadores. Herencia Mltiple. p Manejo de Errores. Entrada/Salida.

152

Herencia
La herencia afecta a variables y mtodos pero no a constructores, mtodos, constructores destructores, operator=, o a elementos friend. Llamada a constructores de superclases (en orden ascendente) y a destructores (en orden descendente) Por cada clase X y clase descendiente Y se permiten automticamente estas operaciones: punteroX=punteroY referenciaX=objetoY referenciaX = objetoY X objX(objY) // constructor copia de X admite objetos Y Ejemplos con: E subclase de P E P clase E Empleado (nombre, edad, sueldo) clase P Persona (nombre, edad) mtodo virtual void mostrar () en clase E l d y P t d i t l id t l Empleado Persona
153

Herencia
Ejemplo operator=
#include <iostream> iostream using std::cout; class A { int val; public: bli void f() {cout << "A::f()\n";} void operator= (int x) { val = x; } ~A() { cout << "A::destructor\n";} A() A::destructor\n ;} }; class B : public A { }; Consola void main() { B b; A a; a = 3; // b = 3; // invlido b.f(); b f() // funciona A a2(b);? } A::f() A::destructor A::destructor

154

Herencia
Ejemplo Constructores
#include <iostream> using std::cout; class A { int val; public: A(int x) : val(x) { cout << "A::A\n"; } }; class B : public A { }; void main() { //B b(2); // invlido //B b; // invlido A a(3); B b=*static_cast<B *>(&a); }
155

// compila pero es dudoso... // &a no es un B*

Herencia Simple
#include <iostream> #include <string> using std::cout; using std::string; class Persona { string nombre; int edad; public: Persona(string name, int age) : edad(age), nombre(name) { cout << "Constructor de Persona\n"; } virtual void mostrar () { cout << "Nombre: " << nombre << "\nEdad: " << edad << "\n"; Nombre: \nEdad: \n ; } virtual ~Persona() { cout<<"destructor de persona\n"; } };

Ejemplo

156

Ejemplo j p
class Empleado : public Persona { long sueldoBruto; public: Empleado(string name, int age, long sueldo) : Persona(name, age), sueldoBruto(sueldo) { cout<< "Constructor de Empleado\n"; t "C t t d E l d \ " } void mostrar() { Persona::mostrar(); P t () cout << "Sueldo Bruto " << sueldoBruto << "\n"; } Consola ~Empleado() {cout<<"destructor de empleado\n";} Constructor de Persona }; } Constructor de Empleado void main() { Persona * p = new E l d ("P d " 27 30000) P Empleado("Pedro", 27, 30000); Empleado * e = new Empleado("Maria", 30, 32000); Persona * p1 = e; p1->mostrar(); delete d l t p; delete e; }

Constructor de Persona Constructor de Empleado Nombre: Maria Edad: 30 Sueldo Bruto 32000 destructor de empleado destructor de persona destructor de empleado destructor de persona

157

Herencia
Acceso a un miembro de una clase:
p.Punto::x=3;
Equivalente a p.x=3;

p.Punto::distanciaOrigen()
Equivalente a p.distanciaOrigen()

Igual que un atributo normal, y tambin Punto::variableStatic=34;

Control de acceso a una clase: declaraciones public, private y protected para miembros de clase. Son accesibles:
private: en la clase y friends public: desde cualquier sitio protected: desde la clase y cualquier clase descendiente X (dentro de la clase X se permite el acceso a partir de objetos de tipo X o descendientes); tambin para friends
158

#include <iostream> using namespace std; class Base { public: void setProtMemb( int i ) { m protMemb = i; } m_protMemb void Display() { cout << m_protMemb << endl; } protected: int m_protMemb; void Protfunc() { cout << "\nAccess allowed\n"; } } base;

Ejemplo protected

class Deriv : public Base { public: void useProtfunc() { Protfunc(); m_protMemb = 4; } } derived; int main() { // base.m_protMemb; base.setProtMemb( base setProtMemb( 0 ); base.Display(); derived.setProtMemb( 5 ); derived.Display(); // base.Protfunc(); b P f () derived.useProtfunc(); }

//error, m_protMemb is protected // OK, uses public access function OK // OK, uses public access function // error, Protfunc() is protected P f () i d // OK, uses public access function in derived class

159

Control de Acceso en Herencia


Como otro miembro, una clase base se puede declarar como private, protected o public.
class B { /* ... */ }; / / class X: public B { /* ... */ }; class Y: protected B { /* ... */ }; class Z: private B { /* ... */ };

La derivacin publica hace la clase derivada un subtipo de la clase base y es lo ms comn. Es la derivacin por defecto en structs. La derivacin protegida y privada se usa para representar detalles de implementacin.
Protected: cuando la clase derivada va a tener hijas a su vez, y la clase base no tiene informacin de interfaz. Private (derivacin por defecto en clases): Para restringir la interfaz de la clase base base.
160

Control de Acceso en Herencia


El especificador de acceso en herencia controla:
el acceso a miembros de la clase base. la conversin de punteros y referencias de la clase derivada a la clase base.

Sea D una clase que hereda de B: q


Si B se hereda como private:
Sus miembros pblicos y protegidos se pueden usar slo por funciones miembros y amigos de D. g Slo amigos y miembros de D pueden convertir de D* a B*.

Si B se hereda como protected:


Sus miembros pblicos y p p protegidos se p g pueden usar slo p funciones miembros y por amigos de D y por funciones miembro y amigos de clases derivadas de D. Slo amigos y miembros de D y amigos y miembros de clases derivadas de D pueden convertir de D* a B*.

Si B se hereda como public:


Sus miembros pblicos se pueden usar por cualquier funcin. Sus miembros protected se pueden usar por miembros y amigos de D y miembros y amigos d clases d i d d D i de l derivadas de D. Cualquier funcin puede convertir un D* a un B*. 161

Redefinicin del Acceso


Un miembro x de una clase A con privacidad p1 en la clase A, se x p1 A puede declarar con otra privacidad distinta p2 con respecto a una clase hija B (heredada con privacidad p3 con respecto a la clase ) A): class A { p1: x; p4: y; } class B : p3 A { p2: A::x; } Esta especializacin tiene prioridad respecto a la declarada por p3 : p3: p4 declara que B::y es A::y, y que tiene privacidad p4 con respecto a clase B p2 declara que B::x es A::x y que tiene privacidad p2 con p2 p2 respecto a clase B 162

Ejemplo herencia public


class A { private: int x; public: int y1; int y2; int y3; protected: int z; }; class B : public A { private: A::y1; // int A::y1; incorrecto // equivalente a // using A::y1; int y3; // otro hueco // de memoria // distinto a A::y3 }; void main() { B b; b.y2=0; b.B::y2=0; // son equivalentes b.A::y1 = 3; // OK // b.y1=0; incorrecto // porque B::y1 es private // en clase B l // b.x=0; incorrecto // p q porque A::x es p private // en clase A // b.A::x, b.B::x // son equivalentes A & a=b; b // correcto t A* p=&b; // correcto }

163

Ejemplo herencia private


class A { l private: int x; public: int i t y; protected: int z; }; class B : private A { l i t public: A::z; // A::x; incorrecto void f () { id B b; b.y=0; // OK A & a=b; // OK A* p=&b; // OK &b // b.x=0; ilegal // b.z=3; ok } }; }

void main() { B b b; // b.y=0; incorrecto b.z=0; // correcto // b.A::y=0; incorrecto b.A::y 0; // A & a=b; // A* p=&b; } incorrecto incorrecto

164

Ejemplo herencia protected


class A { private: int x; public: int y; protected: int z1; int z2; }; class B : protected A { public: A::z1; }; class C : public B { void f () { B b; A & a=b; // correcto A* p=&b; // correcto z2=3; } }; void main() { B b; b.z1=0; C c; c.z1=0; // c.z2=0; incorrecto pero // correcto en clase C // c.y=0; incorrecto porque // y es protected en C // A & a=b; incorrecto pero //correcto en clase C // A* p=&b; incorrecto pero A p &b; // correcto en clase C // es correcto B & bb = c; ? }
165

Privacidad
Son mecanismos de encapsulamiento encapsulamiento. a) Privacidad en miembros de clases:
Privados: operaciones l Pi d i locales a clases l l Protegidos: prohibido usar en clases no descendientes

b) H Herencia con privacidad: i i id d


El uso de herencia private y protected es una alternativa a los mecanismos de a). Herencia private: La clase base proporciona mecanismos de bajo nivel, y no interesa como tipo. La clase derivada no tendr clases hijas. Herencia protected: Parecido a private, pero abre la posibilidad de que la clase derivada tenga clases hijas. Permiten entregar clases a usuarios finales con redefinicin de tipo de privacidad para los miembros que se quiera (por ejemplo con herencia private de su clase padre y modificadores public o protected para ) determinados miembros heredados)
Un caso particular sera, en Java, la especificacin final para una clase, que indica que no se pueden crear subclases
166

Control de Acceso
Tipos dinmicos
// La privacidad se declara con respecto a la // clase esttica pero no dinmica. Ejemplo: class A { public: virtual void f1() {cout << "En clase padre";} virtual void f2() {cout << "En clase padre";} }; class B : public A { private: virtual void f1() {cout << "En clase hija";} A::f2; }; void main() { A a; B b; A & x = b; x.f1(); x.f2(); }

// la clase dinmica de x es B // ligadura dinmica. Mtodos privados en clase hija


167

Polimorfismo
Mtodos Virtuales

Mtodo virtual
virtual en declaracin y opcionalmente p virtual en las especializaciones Tipos:
Puro (=0 en declaracin).
Una clase es abstracta si tiene al menos un mtodo virtual puro. No se pueden crear instancias de clases abstractas. til para d l declarar i t f interfaces.

No puro (con cdigo en todas las definiciones)

Ligadura esttica/dinmica Li d tti /di i

168

Polimorfismo
Mtodos Virtuales

Qu mtodos se llaman?
void main() { A a; B b; A* pa=&a; A* pb=&b; A& x=a; A& y=b; a.f(); // -> A::f() pa->f(); // -> A::f() pb >f(); pb->f(); // -> B::f() > x.f(); // -> A::f() y.f(); // -> B::f() A* x1 = new C(); C* c = dynamic_cast<C*>(x1); A y1=*c; y1.f(); // -> A::f() ( c).f(); (*c) f(); // -> C::f() > }
169

#include <iostream> using std::cout; class A { public: virtual void f() {cout << "A\n";} }; class B : public A { public: bli void f() {cout << "B\n";} }; class C : public B { public: void f() {cout << "C\n";} }; }

Polimorfismo
Mtodos Virtuales

Qu mtodos se llaman?
void main() { A A* x1 = new B(); C* c = dynamic_cast<C*>(x1); A y1=*c; y1.f(); (*c).f(); // error!! }

#include <iostream> using std::cout; class A { public: virtual void f() {cout << "A\n";} }; class B : public A { public: bli void f() {cout << "B\n";} }; class C : public B { public: void f() {cout << "C\n";} };

Destructores virtuales
#include <iostream> #include <string> using std::string; class Persona { string nombre; int edad; public: Persona(string name, int age) : edad(age), nombre(name) { /* */ } virtual ~Persona() {/**/ } // destructor virtual {/ / }; class Empleado : public Persona { long sueldoBruto; l ld B t public: Empleado(string name, int age, long sueldo) : Persona(name, age), sueldoBruto(sueldo) { /* */ } ~Empleado() {/**/} }; void main() { Persona * p = new Empleado("Pedro", 27, 30000); delete p; // sin el destructor virtual no se llama al destructor de Empleado }

171

Ejercicio j
Llamadas a mtodos virtuales en destructores
class Persona { string nombre; int edad; public: Persona(string name, int age) : edad(age), nombre(name) { cout << "Constructor de Persona\n"; } virtual void mostrar () {cout << "Nombre: " << nombre << "\nEdad: " << edad << "\n"; } virtual ~Persona() { cout<<"destructor de persona\n"; mostrar(); } };

Qu sucede si el objeto que se destruye es de tipo empleado? Qu sucedera si mostrar() fuese virtual puro?

Llamadas a Mtodos de Clases Base


Llamadas entre mtodos:
Si Y es base de X, X puede llamar a un mtodo de Y mediante Y::g() ( general que di Y ( ) (ms l super.mtodo() en el caso de Java)
#include <iostream> using std::cout; class A { public: void f() {cout << "A\n";} }; class B : public A { p public: void f() {cout << "B\n";}}; Llamada a clase base class C : public B { public: void f() { A::f(); cout << "C\n";}}; C\n ;}}; void main() { C c; c.f(); }

Consola
A C
173

Herencia y Templates p
Herencia de una clase template
template <int n, class T> class A { private: T array[n]; int dim; public: A() : dim(n) {} }; template <int n, class T t l t i t l T> class B : public A<n, T>{ }; }; void main() { void main() { B<3,int> b; } } B b; }; class B : public A 3 i t { l bli A<3, int>{ public: A() : dim(n) {} template <int n, class T> class A { private: T array[n]; int dim;

Herencia y Templates p
Herencia parametrizada
class A { private: int di i t dim; public: A(int n=0) : dim(n) {} }; template <class Base> class B : public Base{ }; void main() { B<A> b; }

Punteros a Atributos
class A { public: int a; A() : a(5) {} }; class B : public A { public: int b; B() : A(), b(3) {} }; void main() { int A::* p; A a; A * pa = &a; p = &A::a; // slo vlido si a es pblico int ai = a.*p; // 5 int ai2= pa->*p; // 5 B b; B * pb = &b; p = static_cast<int A::*>(&B::b); // casting explcito de int B::* a int A::* int bi = b.*p; // 3 int vvv = a.*p; // sin sentido: -858993460 int bi2 = pb >*p; pb-> p; // 3 int B::* bbp = &A::a; // OK bi = b.*bbp; // 5 bi = a.*bpp; error }

176

#include <iostream> using std::cout; class A { public: void f(i t x) { cout << "A f -> " << x << "\n"; } bli id f(int ) t "A::f "\ " }; class B : public A { int x; public: bli B(int g=100) : x(g) {} void g(int y) { cout << "B::g -> " << y+x << "\n"; } }; void h(int c) { cout << "h -> " << c << "\n"; } id h(i t ) t "\ " void main() { void (A::* pfA)(int); A a; A * pa = &a; pfA = &A::f; (a.*pfA)(1); (pa->*pfA)(2); ( * fA)(2) B b; B * pb = &b; pfA = static_cast<void (A::*)(int)>(&B::g); (b.*pfA)(3); (b * fA)(3) (pb->*pfA)(4); (a.*pfA)(6); void (* pfH)(int) = h; pfH(5); fH(5) void (B::* pfB)(int) = &A::f; (b.*pfB)(3); }

Punteros a Mtodos

Consola
A::f -> 1 A::f -> 2 > B::g -> 103 B::g -> 104 B::g -> -858993454 h -> 5 A::f -> 3

// sin sentido

// OK // (a.*pfB)(3); incorrecto

177

Punteros a Mtodos Virtuales


#include <iostream> using std::cout; class A { public: bli virtual void f(int x) { cout << "A::f -> " << x << "\n"; } }; class B : public A { l bli public: void f(int x) { cout << "B::f -> " << x << "\n"; } };

void main() { void (A::* pfA)(int); B b; A a; A * pa = &b; pfA = &A::f; (a.*pfA)(1); (a *pfA)(1); (pa->*pfA)(2); }

Consola
A::f -> 1 B::f -> 2

178

Castings
tipo(expresion) Tipos primitivos: correcto-COMP, correcto-EJEC Objetos. Para el casting X(Y), si:
X desciende de Y: error-COMP error COMP Y desciende de X: correcto-COMP (llamada a constructor de copia) En otros casos, correcto-COMP si existe el constructor o un operador de casting en la clase
class A { }; A B void main() { B b; A a=A(b); //B b2=B(a); } class B : public A { } }; class C {}; class A {}; class B : public A { public: B () {} B( C & c ) {} }; void main() { C c; B b; b=B(c); }

// error

179

Castings
Punteros (castings al estilo C):
Tipos primitivos: correcto-COMP error-EJEC correcto COMP, error EJEC Objetos: correcto-COMP. Para un casting (X*)Y*, si:
Y desciende de X: correcto-EJEC X desciende de Y: correcto-EJEC cuando el objeto apuntado por Y* es de tipo X o descendiente. d di t En otros casos, error-EJEC

Referencias

Anlogo a punteros
Uso de dynamic_cast<>, o static_cast<>
class A {}; class B : public A { public: B () {} }; void main() { A * a = new B; B * b = (B*)a; }

180

Castings
Uso de =

Punteros:
Tipos p p primitivos: vlido si son del mismo tipo p Objetos: punteroclase=punteroClase Descendiente ; Descendiente; void*=cualquierPuntero

Incorrecto: I t
variable-referencia-no-const=elemento-const

181

Castings
Ejemplos
#include <iostream> using std::cout; class P { public: virtual void imprime() { cout << "P\n";} }; class E : public P { public: void imprime() {cout << "E\n"; } }; void main() { E e; P p; E* pE; P* pP=&e; pE=(E*)pP; // OK // pE=pP; error-COMP pP->imprime(); (*pP).imprime(); ((P)e).imprime(); ((P*)&e)->imprime(); }

Consola
E E P E

182

#include <iostream> using std::cout; using std::ostream;

Castings
Ejemplo Complejos, version a (i) Ej l C l j i

class Complejo { private: double x; double y; public: Complejo (double x, double y) : x(x), y(y) {} Complejo (double x) : x(x), y(0) {} // operador como mtodo de objeto Complejo operator+ (const Complejo & c) const { Complejo s(x+c.x,y+c.y); return s; } friend ostream& operator<<(ostream& cout, const Complejo & c); }; ostream& operator<<(ostream& cout, const Complejo & c) { return cout << "[" << c.x << "+" << c.y << "i]\n"; } // debe devolver una referencia ostream& void main() { Complejo c1(2,3), c2(4,5); Complejo s1=c1+c2; Complejo s2=c2+2; // casting implcito (invlido si el constructor es explicit cout << "La suma s1 es:" << s1; // 6+8i cout << "La suma s2 es:" << s2; // 6+5i 183 }

#include <iostream> using std::cout; using std::ostream; class Complejo { private: double x; double y; Ejemplo Complejos, version public: Complejo ( p j (double x, double y) : x(x), y(y) {} , ( ), Complejo (double x) : x(x), y(0) {} friend Complejo operator+ (const Complejo & c1, const Complejo & c2); friend ostream& operator<< (ostream& cout, const Complejo c); }; Complejo operator+(const Complejo & c1, const Complejo & c2){// operador como funcin Complejo s(c1.x+c2.x,c1.y+c2.y); return s; } // si tuviramos tambin la definicin Complejo::operator+(const Complejo&)const se // produciran errores de ambigedad

Castings
b (i)

ostream& operator<<(ostream& cout, const Complejo c) { return cout << "Complejo[" << c.x << "+" << c.y << "i]\n";} // devolver una referencia ostream& void main( ){ ( Complejo c1(2,3), c2(4,5); Complejo s1=c1+c2, s2=c2+2, s3=3+c2; // necesario operator+ como funcin cout << "La suma s1 es:" << s1; // 6+8i cout << "La suma s2 es:" << s2; // 6+5i La es: cout << "La suma s3 es:" << s3; // 7+5i }

184

Acceso a Tipo Dinmico (RTTI)


Run-Time Run Time Type Information:
dynamic_cast, typeid, type_info

Tipo polimrfico:
Tiene o hereda mtodos virtuales

Acceso al tipo dinmico en C++


En tipo polimrficos Mediante typeid(puntero|objeto)
Devuelve una referencia a un objeto constante de la clase type_info
type_info::name() bool type_info::operator==(const type_info &)

Hacer #include <typeinfo> Para tipos no polimrficos, devuelve tipos estticos polimrficos
185

Acceso a Tipo Dinmico


#include <iostream> #include <typeinfo> class Base { public: virtual void vvfunc() {} }; class Derived : public Base {}; using namespace std; int main() { Derived* pd = new Derived; Base* pb = pd; cout << typeid( pb ) name() << endl; ).name() cout << typeid( *pb ).name() << endl; cout << typeid( pd ).name() << endl; cout << typeid( *pd ).name() << endl; delete pd; }

//prints "class Base *" class //prints "class Derived" //prints "class Derived *" //prints "class Derived"
186

Acceso a Tipo Dinmico


#include <iostream> #include <typeinfo> using namespace std; template < typename T > T max( T arg1, T arg2 ) { cout << typeid( T ).name() << "s compared." << endl; return ( arg1 > arg2 ? arg1 : arg2 ); } int main() { typeid(int) == typeid(int&); // evalua a true }

187

Castings C++
Uso habitual en punteros o referencias
static_cast
Anlogo al casting clsico de C, pero da errores en tiempo de compilacin para conversiones imposibles Aplicable a cualesquiera tipos (no necesario polimrficos) No aplicable cuando no se g p garantice la conservacin de const

dynamic_cast
Entre tipos p p polimrficos ( y B). Para una expresin de tipo (A ) p p puntero o referencia. Ejemplo para punteros: B* p=dynamic_cast<B*>(expresion);
Devuelve NULL si la conversin es imposible Para referencias, se produce una excepcin. P f i d i

Ms seguro, pero ms ineficiente que el static_cast

const_cast (Eliminar/Aadir const a expresiones) reinterpret_cast (Hacer conversiones arbitrarias entre i t t t (H i bit i t tipos)

188

Castings C++ g
Ejemplo
#include <iostream> #include t #i l d <typeinfo> i f class Base { public: virtual void vvfunc() {} i t l id f () }; class Derived : public Base {}; using namespace std; i td int main() { Derived d; Derived & pd = d; Base b B b; Base & pb = b; try { pd = d d dynamic_cast<Derived&>(pb); i t D i d& ( b) } catch(bad_cast bc) { cout << "cannot cast a " t " t t << typeid(pb).name() << " to a " << typeid(pd).name() << "\n"; } }

Ejercicio
#include <iostream> #include <string> #include <vector> #include <map> #include <sstream> using namespace std; class Item { string nombre; double precio; public:

Dadas las clases Item y LineaPedido, implementa unas clases para el manejo de pedidos con la siguiente funcionalidad: Obtencin del precio total. Aadir lnea de pedido. Obtencin de pedido por su ID. Un pedido puede ser simple o compuesto. Estos ltimos estn compuestos d pedidos ( i l o compuestos). t de did (simples t ) Cada pedido tiene un ID nico que se asigna automticamente.

Item(string nombre, double precio) : nombre(nombre) precio(precio) {} nombre nombre(nombre), double getPrecio() const {return precio;} string getNombre() const {return nombre;} }; class LineaPedido { int num; Item * item; public: LineaPedido(int num, Item * i ) : num(num), item(i) {} double getPrecio() const {return num*item->getPrecio(); } };

Ejercicio
Ejemplo cdigo cliente
void main() { Item boligrafo("boligrafo", 3), lapicero( lapicero 2), lapicero("lapicero", 2) cuaderno("cuaderno", 10), folios("folios", 5), borrador("borrador", 1.5); PedidoSimple ps1; ps1.anyadeLinea(10, &boligrafo). anyadeLinea(3, &borrador). anyadeLinea(4, anyadeLinea(4 &lapicero); PedidoCompuesto pc1; pc1.anyadePedido(&ps1); PedidoCompuesto pc2; pc2.anyadePedido(&ps1); pc1.anyadePedido(&pc2); pc1 anyadePedido(&pc2); cout << pc1 << "\n" << pc1[1] << "\n" << ps1 << "\n" \n << Pedido::getPedido("P0")->getPrecio() << "\n" << Pedido::getPedido("P1")->numPedidos() << "\n"; } Salida Pedido #P1, precio= 85 #P1 Pedido #P2, precio= 42.5 Pedido #P0, precio= 42.5 42.5 2

class Pedido{ static long int max_id; static map<string, Pedido *> pedidos; int id; public: // mtodos virtuales puros virtual double getPrecio() const = 0; virtual int numPedidos() const = 0; Pedido() { id = max_id++; // asigna el ID pedidos[getId()] = this; // almacena en diccionario } string getId() const { stringstream s; s << "P" << id; return s.str(); s str(); } static Pedido * getPedido(string clave) { return pedidos[clave]; } virtual ~Pedido() { map<string, Pedido *>::iterator i = pedidos.find(getId()); pedidos.erase(i); } }; long int Pedido::max_id = 0; map<string, Pedido *> Pedido::pedidos;

Solucin

Solucin
class PedidoSimple : p p public Pedido{ { vector<LineaPedido *> linea_pedidos; public: PedidoSimple & anyadeLinea(int num, Item * i) { linea_pedidos.push_back(new LineaPedido(num, i)); return *this; } double getPrecio() const { double acum = 0.0; for ( vector<LineaPedido *>::size_type i = 0; i < linea_pedidos.size(); acum += linea_pedidos[i++]->getPrecio() ); return acum; } ~PedidoSimple() { vector<LineaPedido *>::iterator i = linea_pedidos.begin(); while (i != linea_pedidos.end()) { delete *i; i++; } } int numPedidos() const { return 1; } };

Solucin
class PedidoCompuesto : public Pedido { vector<Pedido*> pedidos; public: void anyadePedido(Pedido * p) {pedidos.push_back(p); } double getPrecio() const { double acum = 0.0; for ( vector<Pedido *>::size_type i = 0; i < pedidos.size(); acum += pedidos[i++]->getPrecio() ); return acum; } Pedido & operator[] (vector<Pedido*>::size_type idx) const { if (idx < pedidos size()) return *pedidos[idx]; pedidos.size()) pedidos[idx]; else throw "not found"; } int numPedidos() const { return int(pedidos.size()); } }; ostream & operator << (ostream & os, const Pedido & p) { os << "Pedido # << p.getId() << ", precio= " << p.getPrecio(); Pedido #" p getId() precio p getPrecio(); return os; }

Ambigedad
Sobrecarga

Dos declaraciones d f D d l i de funcin o mtodo son i t d incompatibles (produciendo un error de compilacin) si tienen el mismo nombre y sus argumentos son equivalentes. Ejemplos de argumentos equivalentes:
Renombramiento del parmetro. Argumento Obligatorio Argumento Opcional Argumento const Argumento no const
Para un tipo X que es primitivo o clase:
X X* const X X* const
195

Ambigedad
Sobrecarga

Incompatibles:
void f (int x) {...} void f (int y) {...} void f (int x) {...} void f (int x=2) {...} void f (int x) {...} void f (const int x) {...} void f (Complejo x) {...} void f (const Complejo x) {...} void f (int* p) {} (int void f (int* const p) {} (int void f (Complejo* p) {} void f (Complejo* const p) {} void f () int f()

Compatibles:
void f (int* p) {} (int void f (const int* p) {} int void f (Complejo* p ) {...} void f (const Complejo* p) {...} void f (Complejo& p ) {...} void f (const Complejo& p) {...} void f (Complejo x) {} void f (Complejo & x) {}
196

Ambigedad
Sobrecarga

Se S pueden t d tener dos d fi i i d definiciones compatibles y producirse una llamada ambigua. Mensaje:
ambiguous call to overloaded function

Ejemplo:
Definiciones
void f (Complejo x) {} ( p j ) void f (Complejo & x) {} ( p j )

Llamada
Complejo c; f(c);
197

Ambigedad
Conversin implcita y Sobrecarga

Ejemplo 2
class A { public: double x; A (double x) : x(x) {} }; class B { public: double x; B (double x) : x(x) {}

};
void f(A a){/**/} void f (B b) {/**/}

Llamada: f(0);
198

Ambigedad
Parmetros variables y Sobrecarga

Ejemplo 3
Definiciones D fi i i
void f(int x){} void f(int x ...) {/**/}

Llamada
f(0);

Ejemplo 4 j p
Definiciones
void f(int x=0){} void f(int x ...) {/**/}

Llamada
f(0);
199

Desambiguacin
Sobrecarga
Varias definiciones compatibles de funciones p globales o mtodos de una clase

Desambiguacin:
Para varias definiciones compatibles y una f llamada no ambigua, existen reglas de desambiguacin d bi i

200

Desambiguacin
Reglas

Determinar las definiciones candidatas


Aquellas en donde son posibles las asignaciones mediante = para los parmetros.

Dadas 2 definiciones candidatas D1 y D2, se dice que D1 es ms especfica que D2 si es posible la p q p asignacin ParametrosD2=ParametrosD1
Ejemplo void f(Empleado) es ms especfica que void f(Persona) f(Persona)

De entre las definiciones candidatas, buscar la ms especfica (si hay ms de una sera una llamada ambigua).
201

Desambiguacin
Excepciones

Excepcin 1:
p para las definiciones:
D1: void f(int x){...} ( y){...} D2: void f(double y){ }

se tendra que D1 es ms especfica que D2 y viceversa, pero se considera D1 ms especfica p por razones obvias. Por tanto:
f(3) D1
202

Desambiguacin
Excepciones

Excepcin 2:
class B {}; class A : public B {}; class C { public: C(A a){} };

Dadas las definiciones:


D1: void f(B b){ } b){...} D2: void f(C c){...}

Y la llamada:
A a; f(a) // D1

Ninguna es ms especfica que la otra, pero se considera D1 ms 203 especfica priorizando la herencia frente al casting.

Desambiguacin
1. A subclase de B, B subclase de C;
void f (B b){}; void f(C c){}; ( ){}; ( ){};
A a; f(a) void f(B)

2. A subclase de B, X clase con X(A), Y clase con Y(A)


void f (X); void f (Y);
A a; f(a) llamada ambigua

204

Desambiguacin
const
// Definiciones compatibles (punteros): void d(Complejo * i){} // Definicin 1 void d(const Complejo * i){} // Definicin 2 void main() { const Complejo c1; Complejo c2; d(&c1); // Definicin 2 (la nica candidata) ( ); ( ) d(&c2); // Definicin 1 . De entre 2 // candidatas se busca la ms especfica }

205

Desambiguacin
const
// Definiciones compatibles (referencias): void d(Complejo & i){} // Definicin 1 void d(const Complejo & i){} // Definicin 2 void main() { const Complejo c1; Complejo c2; d(c1); // Definicin 2 (la nica candidata) ( ); ( ) d(c2); // Definicin 1 . De entre 2 // candidatas se busca la ms especfica }

206

Desambiguacin
const
// D alguna f De l forma, l los mtodos d clases equivalen t d de l i l // a funciones globales con un parmetro ms: this class A { p public: void f () { // Definicin 1 // Siempre se cumple que "A* const this" }; void f () const { // Ahora adems se cumple que "const A* this" }; }; void main(int argc, char* argv[]) { A a1; a1.f(); a1 f(); // Definicin 1 (de entre 2 candidatos) const A a2; a2.f(); // Definicin 2 (de entre 1 candidato) } Ejemplo: iterator vector::begin(); const_iterator vector::begin() const;

207

Desambiguacin
polimorfismo
Casos:
Sobrecarga (overloading) Sobreescritura (overriding)

Entre 2 clases relacionadas por herencia:


Mtodos virtuales:
Se puede tener 2 definiciones incompatibles si el tipo de retorno es el mismo (o es covariante).

Mtodos no virtuales:
Se puede tener 2 definiciones incompatibles

Pasos para ejecutar objeto.mtodo (ejemplos en sobrecarga.cpp):


En tiempo de compilacin
Desambiguacin de sobrecarga en la clase de objeto

En tiempo de ejecucin
Si el mtodo es virtual, se considera la definicin en la clase dinmica de virtual objeto
208

Desambiguacin
Mtodos no virtuales
#include <iostream> using std::cout; class C { public: int f(int x) { cout << "C::f -> " << x << "\n"; return 0;} int f(int x) const { cout << "C::f const -> " << x << "\n"; return 0;} }; class B : public C { public: void f(int x) { cout << "B::f\n"; } }; void main() { B b; // int a = b.f(3); // error de compilacin b.f(1); b.C::f(2); const B bc; //bc.f(3); // error de compilacin bc.C::f(3); }

B::f C::f -> 2 C::f const -> 3

Consola

209

#include <iostream> using std::cout; using std::endl;

Desambiguacin
polimorfismo: ejemplo

class B; class A { public: virtual void f (A* x) {cout << "Funcion f (A*) en clase A" << endl;} virtual void f (B* x) {cout << "Funcion f (B ) en clase A" << endl;} (B Funcion (B*) A }; class B : public A { public: void f (A* x) { cout << "Funcion f (A ) en clase B" << endl;} (A Funcion (A*) B void f (B* x) {cout << "Funcion f (B*) en clase B" << endl; } }; void main() { B b; A a; A & x = b; a.f(&a); Consola a.f(&b); a f(&b); Funcion f (A*) en clase A x.f(&a); Funcion f (B*) en clase A x.f(&b); Funcion f (A*) en clase B x.f(&x); Funcion f (B*) en clase B b.f(&a); b f(&a); Funcion f (A ) en clase B (A*) b.f(&b); Funcion f (A*) en clase B cout << "Final"; Funcion f (B*) en clase B }

Funciones Virtuales
Retorno covariante
class A {}; class B : public A {}; class Base { public: virtual A* getA( ) const { return new A; } }; class Derived : public Base{ public: virtual B* getA( ) const { return new B; } }; void main() { Derived * d = new Derived; A * a = d->getA(); }

211

Funciones Virtuales
Retorno covariante
class Shape { public: virtual ~Shape() { } virtual void draw() = 0; virtual void move() = 0; virtual Shape* clone() const = 0; // Uses the copy constructor virtual Shape* create() const = 0; // Uses the default constructor }; class Circle : public Shape { public: Circle* clone() const; // Covariant Return Types; see below Circle* create() const; // Covariant Return Types; see below };
... ...

void userCode(Shape& s) { Shape* s2 = s.clone(); Shape* s3 = s.create();


...

Circle* Circle::clone() const { return new Circle(*this); } Circle* Circle::create() const { return new Circle(); }

delete s2; delete s3;

// You need a virtual destructor

212

Desambiguacin
Ocultacin
// motivado por la existencia de herencia mltiple class A { public: void f (i t) {} id (int) {}; }; class B : public A { public: void f () {}; }; class C : public B {}; void main() { () C c; // c.f(3); error c.A::f(3); c A::f(3); c.f(); // correcto }

213

Ejercicio
class Cl kTi l ClockTimer : public S bj t { bli Subject public: ClockTimer(); tua t GetHour(); virtual int Get ou (); virtual int GetMinute(); virtual int GetSecond(); void Tick() { // update internal time-keeping state // ... Notify(); } };

Disea una serie de clases que permitan que una instancia de ClockTimer pueda actualizar un nmero arbitrario de instancias de relojes de distinto tipo (analgicos, digitales, etc.). Cuando los distintos relojes reciben una invocacin al mtodo Update(), deben actualizarse (llamada a Draw())

Solucin
Patrn de diseo Observer
class Subject; class Observer { public: virtual ~ Observer(); p ( j g j ) ; virtual void Update(Subject* theChangedSubject) = 0; protected: Observer(); }; class Subject { public: virtual ~Subject(); virtual void Attach(Observer*) {observers->push_back(o); } virtual void Detach(Observer*) {observers->remove(o); } virtual void Notify() { for ( List<Observer*>::iterator i = _observers.begin(); i! observers.end(); i++) i!=_observers.end(); _i ) i->Update(this); } protected: Subject(); S bj t() private: List<Observer*> *_observers; };

class DigitalClock: public Widget, public Observer { public: virtual ~DigitalClock(){_subject->Detach(this);}

Solucin

DigitalClock(ClockTimer* s) : _subject(s) { _subject->Attach(this); } virtual void Update(Subject* changed) {if (changed == _subject) Draw();} Update(Subject subject) virtual void Draw(); // defines how to draw the digital clock private: ClockTimer ClockTimer* _subject; subject; }; void DigitalClock::Draw () { // g get the new values from the subject j int hour = _subject->GetHour(); int minute = _subject->GetMinute(); // etc. // draw the digital clock } class AnalogClock : public Widget, public Observer { public: AnalogClock(ClockTimer*); virtual void Update(Subject*); virtual void Draw(); // ... };

Operadores
No se pueden definir operadores nuevos nuevos. Al hacer sobrecarga, se mantienen l reglas h b ti las l de precedencia del operador. Se pueden definir como funciones globales o como mtodos: t d
Necesario definirlos de las 2 formas en caso de necesidad de conmutatividad
Algunas llamadas pueden ser ambiguas

Los operadores como funciones globales suelen ser friend de las clases de sus argumentos

217

class A { public: int* v; A(int* v) : v(v) {} int& operator[] (int i) { return v[i]; } }; // Al menos un parmetro debe ser un objeto int operator+(int x, A & a) {return 0;} void main() { int numeros[2]={1, 2}; numeros[2]={1 A a(numeros); int x; x=3+a; x=operator+(3,a); // es equivalente x=operator + (3,a); // equivalente tambin x=3-4; // x=operator-(3 4); ERROR x operator (3,4); numeros[0]=3; // numeros.operator[](0)=3; ERROR a[0]=4; a.operator[](0)=4; // equivalente }

Operadores
Ejemplo

218

Operadores
Ejemplo
class F h { l Fecha public: Fecha operator+ (int dias) { ... } friend Fecha operator+ (int dias, Fecha & f); friend Fecha operator+ (Fecha & f, int dias); }; Fecha operator+ (int dias, Fecha & f) { ... // puede acceder a variables privadas de f } Fecha operator+ (Fecha & f, int dias) { ... // puede acceder a variables privadas de f } void main(int argc char* argv[]) { argc, Fecha f; //f=f+3; llamada ambigua f=operator+(f,3); f=f.operator+(3); f=3+f; // correcto }

219

Algunos Operadores Importantes


Ejemplos:
ostream& ostream::operator<<(double n); ostream& ostream::operator<<(const char *s); ( )

Operadores = y ==
Operador == definido como funcin global ==
Entre punteros:
Tipos primitivos: del mismo tipo Objetos: de mismo tipo o relacionados po herencia Obje os del s o po e ac o ados por e e c a

Entre cualesquiera tipos primitivos no punteros No definido por defecto en cualquier clase

Operador = definido por defecto como mtodo de objeto para cualquier clase
No definible N d fi ibl como f funcin global i l b l
220

Operator == p
#include <iostream> using std::cout; class B { int h; public: B(int x = 0) : h(x) {cout<<"const B\n";} {cout<< const B\n ;} int getVal() const { return h; } };

class A { int n; public: A(int x=0) : n(x) {cout<<"const A\n";} {cout<< const A\n ;} bool operator == (B & b) { return n == b.getVal(); } // Puede definirse como mtodo o como funcin global }; void main() { A a, a2; B b; a == b ? cout << "iguales\n" : cout << "distintos\n"; iguales\n distintos\n ; &a == &a2 ? cout << "punteros iguales\n" : cout << "punteros distintos\n"; // &a == &b ? cout << "punteros iguales\n" : cout << "punteros distintos\n"; error }

221

Lista de Operadores
Sobrecargables
Unarios (uso opcional de parntesis en argumento)
+, -, ++, --, !, ~ (de bit), &(direccin), sizeof, (tipo)

Binarios
+, -, *, /, %, <<, >>, & (de bit), | (de bit), ^ (de bit), ==, !=, >, <, >=, <=, &&, ||, ,

Binarios (de asignacin)


=, +=, -=, *=, /=, %=, >>=, <<=, &=, |=, ^=

Sobrecargables (con precaucin)


->, [], () llamada a funcin, new, new [], delete, delete []

No sobrecargables
., ::, ? : . , :: , ? :

Ejemplos: complejos.cpp, cadenas.cpp

222

#include <iostream> using std::ostream; using std::ios; using std::cout; class complejo { private: double real, imag; public:

Ejemplo

complejo() : real(0), imag(0) {}; complejo(double re, d bl i 0 0) : real(re), i l j (d bl double im=0.0) l( ) imag(im) {} (i ) complejo(const complejo & c) : real(c.real), imag(c.imag) {}
// Sobrecarga de operadores aritmticos complejo operator+ (const complejo&) const; // Alternativa como operador global: //friend complejo operator+ (const complejo&, const complejo&); complejo operator- (const complejo&) const; complejo& operator= (const complejo&); // Sobrecarga del operador de asignacin, no se puede definir como operador global g operator int() const; // Sobrecarga del operador de casting (sin tipo de retorno); double & operator[] (int i); // Sobrecarga del operador [] complejo& operator ++ (); // Sobrecarga del operador unario ++ prefijo, como el resto de los operadores unarios complejo operator ++ (int x); // operador unario ++ postfijo, el argumento nunca se utiliza y puede ser de cualquier tipo friend bool operator== (const complejo&, const complejo&); // Sobrecarga de operadores de comparacin //bool complejo::operator== (const complejo&) const; // Alternativa como operador de objeto friend bool operator!= (const complejo&, const complejo&); friend ostream& operator<< (ostream&, const complejo&); // Sobrecarga del operador de insercin en el flujo de salida // Una funcion global que se comportara como el operador = friend complejo & asignar (complejo&, const complejo&); 223 };

Ejemplo
complejo complejo::operator+ ( p j p j p (const complejo &a) const { operador miembro + sobrecargado p j ) {// p g complejo suma (real+a.real, imag+a.imag); return suma; } complejo complejo::operator- (const complejo &a) const {// operador miembro - sobrecargado complejo resta (real a.real, imag a.imag); (real-a real imag-a imag); return resta; } complejo& complejo::operator= (const complejo &a) {// operador miembro de asignacin sobrecargado real = a.real; imag = a.imag; i i return *this; } complejo::operator int() const { // operador de casting return (int)real; } double & complejo::operator[] (int i) { if (i==0) return real; else return imag; } complejo & complejo::operator ++ () {// operador unario ++ prefijo real++; imag++; return *this; } complejo complejo::operator ++ (int x) {// operador unario ++ postfijo real++; imag++; return *this; }

224

Ejemplo
bool operator== (const complejo& a, const complejo& b) {// operador friend de test de igualdad sobrecargado return (a.real==b.real && a.imag==b.imag); } // operador friend de test de desigualdad sobrecargado bool operator!= (const complejo& a, const complejo& b) { return (a.real!=b.real || a.imag!=b.imag); (a real!=b real a imag!=b imag); } ostream& operator << (ostream& co, const complejo &a) {// operador friend << sobrecargado co << a.real; o g co.setf(ios::showpos); long fl = co set ( os s o pos); co << a.imag << "i"; co.flags(fl); return co; } complejo & asignar (complejo & c1, const complejo& c2) {// "operador" = "definido" como funcion global c1.real = c2.real; c1.imag = c2.imag; return c1; } void main() { complejo c1(2, 3), c2 = 4; complejo c3 = c1+c2; cout << c3 << \n << (c1==c2); }

225

#include <iostream> using namespace std; class Figura { public: virtual ostream& put (ostream &s) const = 0; virtual ~Figura(){} // no se permiten destructores virtuales puros }; class Circulo : public Figura { double cx cy rad; cx, cy, public: Circulo(double x, double y, double r): cx(x), cy(y), rad(r) {} ostream& put (ostream &s) const { return s << "circulo{[" << cx << ", " << cy << "], rad << rad << "}\n"; circulo{[ , ], rad=" }\n ; } ~Circulo() {} }; class Rectangulo : public Figura { double x1, y1, x2, y2; public: Rectangulo(double x1, double y1, double x2, double y2): x1(x1), y1(y1), x2(x2), y2(y2) {} ostream& put (ostream &s) const { return s << "rect{[" << x1 << ", " << y1 << "] [ << x2 << ", "<< y2 << "]}\n"; rect{[ ], [" << ]}\n ; } ~Rectangulo() {} }; inline ostream& operator << (ostream& s, const Figura& f) { return f.put(s);} void main() { Figura ** figs = new Figura*[2]; figs[0] = new Circulo(10, 10, 0.5); figs[1] = new Rectangulo(10, 10, 12, 12); cout << *figs[0] << *figs[1]; delete [] figs; }

Operator <<

Consola circulo{[10, 10], rad=0.5} circulo{[10 10] rad=0 5} rect{[10, 10], [12, 12]}

#include <iostream> #include <string> #include <vector> using namespace std; class Assoc { struct Pair { string name; double val; Pair(string "" double 0) P i ( t i n="", d bl v=0) : name(n), val(v) {} ( ) l( ) }; vector<Pair> vec; Assoc(const Assoc&); // privado para evitar copias Assoc& operator=(const Assoc&); // privado para evitar copias public: Assoc() {} const double& operator[] (const string&); double& operator[](string&); void print_all() const; print all() }; double& Assoc::operator [](string &s) { for (vector<Pair>::iterator p=vec.begin(); p!=vec.end(); ++p) if (s==p->name) return p->val; vec.push_back(Pair(s,0)); ec p sh back(Pair(s 0)) return vec.back().val; } void Assoc::print_all() const { for (vector<Pair>::const_iterator p=vec.begin(); p!=vec.end(); ++p) cout << p->name << ": " << p->val << "\n"; } void main() { string buf; Assoc vec; while (cin>>buf) vec[buf]++; vec.print_all(); }

Operator [ ]

Operador -> >


#include <iostream> class Ptr { struct X { int m; } x; public: X * operator->(); }; Ptr::X * Ptr::operator->() { return &x; t & } void main() { Ptr p; p->m=5; //int n = p->; // error p >; }

Su uso principal es crear smart pointers: objetos que actan como punteros y que h hacen algo cada vez l d que se accede a un miembro. Ej.: cargar datos desde disco si los datos no estn en memoria. Debe ser un miembro de la clase, y debe retornar un p puntero a un objeto al q j que se le pueda aplicar ->.

#include <iostream> #include <string> using namespace std; struct Rec { string name; i }; class Rec_ptr { const char * identifier; Rec * in_core_address; public: Rec_ptr(const char * p) : id tifi ( ) i R t( t h ) identifier(p), in_core_address(0) {} dd (0) ~Rec_ptr() { write_to_disk(in_core_address, identifier); } Rec * operator->(); }; Rec * Rec_ptr::operator->() { if (in_core_address==0) in_core_address = read_from_disk(identifier); return in_core_address; t i dd } void update(const char* s){ Rec_ptr p(s); R t ( ) p->name="Pedro"; }

Operador -> >

// obtener Rec_ptr para s bt R t

#include <iostream> #include <string> #include <sstream> using std::string; using std::stringstream; using std::cout; class Nam { string s; public: Nam (string & st) : s(st) {} operator string() const { return s;} }; class Num { int x; public: Num (int n) : x(n) {} operator int() const { return x;} operator Nam() const { stringstream st; st << x; return st.str(); } }; void main() { Num n(8); Nam nam(string("")); int x = n; nam=n; cout << string(nam); }

Operadores de casting

230

#include <iostream> using std::cout; using std::endl; class A { int a; public: A(int n=0) : a(n) {} A& operator++ () { cout << "prefijo\n"; ++a; return *this; this; } A& operator++ (int n) { cout << "sufijo\n"; ++a; return *this; } }; void main() { A a(6), b; b = ++a; // b = 7; b = a++; // b = 8; a = 8; ojo con la precedencia!! }

Operador ++ p
Prefijo y Sufijo

231

#include <iostream> #include <string> #include <sstream> using namespace std; struct A { virtual virtual virtual };

Operadores
Ejemplo

// clase con todos los miembros pblicos A& operator++ () = 0; A& operator+ (A &) = 0; string comoString () = 0;

struct B : public A { int x; B () {} B (int x) : x(x) {} B& operator+ (A & a) { B* b=new B(); // memoria dinmica a liberar if (B* ba = dynamic_cast<B*>(&a)) { b->x=x+ba->x; } return *b; } ...
232

Operadores
Ejemplo
... B& operator++ () { x++; return *this; } string comoString () { stringstream s; t i t s << x; return "B[" + s.str() + "]"; } }; ostream& operator<< (ostream& co, A & a) { return co << a comoString(); a.comoString(); } ...
233

Operadores
Ejemplo
void main() { B b1(3), b2(4); cout << "Valores: " << b1 << "," << b2 << endl; ++b1; ++b2; b2; cout << "Valores despues: " << b1 << "," << b2 << endl; A & a = b1+b2; cout << "Suma: " << a << endl; dl // Equivalente a lo siguiente (ligadura dinmica): // B suma =dynamic_cast<B&>(a); // cout << "Suma:" << su a << e d ; Su a suma endl; delete &a; } Resultado Valores: B[3],B[4] Valores despues: B[4],B[5] Suma: B[9] Suma: B[9]
234

#include <iostream> #include <string> using std::strcpy; using std::strcmp; using std::ostream; using std::istream; using std::string; using std::cin; using std::cout;

Ejemplo Operadores j p p
Una clase String

class String { struct Srep; // para almacenar el string en s, compartido por varios String Srep * rep; class Cref; // clase ayuda para implementar el operador [] public: class Range {}; // para excepciones String(); String(const char *); String(const String&); String& operator=(const char *); String& operator=(const String&); ~String(); // Operadores de acceso void check(int i) const; char read(int i) const; void write(int i, char c); Cref operator[](int i); char operator[](int i) const; int size() const; // concatenacin y funciones tiles // String x = "" // String x = "abc" // String x = other_string (semntica de valor) // x = "abc" // x = other_string (semntica de valor)

235

String operator+= (const String&); String operator+= (const char *); friend ostream& operator<< (ostream&, const String&); friend istream& operator>> (istream&, String&); friend bool operator == (const String& x, const char * s); friend bool operator == (const String& x, const String& y); friend bool operator != (const String& x, const char *s); friend bool operator != (const String& x, const String& y); }; String operator+(const String&x, const String&y); String operator+(const String&x, const char *s); struct String::Srep{ char *s; // puntero a elementos int sz; // numero de caracteres int n; // cuenta de referencias Srep(int nsz, const char * p) : n(1), sz(nsz), s(new char[nsz+1]) { strcpy(s,p); } ~Srep() {delete [] s; } Srep * get_own_copy() { // clonar si es necesario if (n == 1) return this; n--; return new Srep(sz, s); } void assign(int nsz, const char * p) { if (sz!=nsz) { delete [] s; sz = nsz; s = new char[sz+1]; } strcpy(s, p); } private: // para prevenir copia Srep (const Srep&); Srep& operator=(const Srep&); };

Ejemplo String

236

class String::Cref{ friend class String; String & s; int i; Cref(String &ss, int ii) : s(ss), i(ii) {} Cref(const Cref& r) : s(r.s), i(r.i) {} Cref(); public: operator char() const { s.check(i); return s.read(i); } void operator=(char c) {s.write(i, c); } }; String::String() { // el string vaco es el valor por defecto rep = new Srep(0, ""); } String::String(const String& x) { // constructor copia x.rep->n++; rep = x.rep; } String:: String() String::~String() { if (--rep->n==0) delete rep; } String& String::operator= (const String& x) { x.rep->n++; x rep >n++; if (--rep->n==0) delete rep; rep = x.rep; return * this; } String::String(const char * s){ rep = new Srep(strlen(s), s); }

Ejemplo String
// devolver valor // cambiar valor

// compartir la representacin

// asignacin copia // antes por si "st=st" st=st

237

String& String::operator = (const char * s){ if (rep->n==1) rep->assign(strlen(s), s); else { rep->n--; rep = new Srep(strlen(s), s); } return * this; }

// reciclar Srep

Ejemplo String

inline void String::check(int i) const { if (i<0 || rep->sz<=i) throw Range(); } inline char String::read(int i) const { return rep->s[i]; } inline void String::write(int i, char c) { rep = rep->get_own_copy(); rep->s[i] = c; } inline String::Cref String::operator[](int i) { check(i); return Cref(*this, i); } inline char String::operator[](int i) const { check(i); return rep->s[i];} inline int String::size() const { return rep->sz; } inline bool operator == (const String& x, const char * s) {return strcmp(x.rep->s, s)==0;} inline bool operator == (const String& x, const String& y) {return strcmp(x.rep->s, y.rep->s)==0;} inline bool operator != (const String& x, const char *s) {return strcmp(x.rep->s, s)!=0;} inline bool operator != (const String& x, const String& y) {return strcmp(x.rep->s, y.rep->s)!=0;} ostream& operator<< (ostream& o, const String& s){ return o << s.rep->s; } istream& operator>> (istream& i, String& s){ string st; i >> st; s=st.c_str(); t t () return i; }

238

Ejemplo String
// ---------------------------------------------------------------------------------------------------// user code d // ---------------------------------------------------------------------------------------------------String f(String a, String b) { a[2] = 'x'; char c = b[3]; cout << "en f: " << a << ' ' << b << ' ' << c << '\n'; return b; } void main() { String x, y; x cout << "introduce 2 cadenas\n"; cin >> x >> y; cout << "la entrada fue " << x << ' ' << y << '\n'; String z = x; // constructor copia y=f(x, y); if (x != z) cout << "x corrupto"; x[0]='!'; if (x==z) cout << "la escritura fallo\n"; la fallo\n ; cout << "exit: " << x << ' ' << y << ' ' << z << ' ' <<'\n'; }

239

Herencia Mltiple
Sintaxis:
class X : [virtual] [tipo_acceso] clasePadre1, [virtual] [tipo acceso] clasePadre2 {}; [tipo_acceso] { };
Tipo_acceso: public, private y protected Acceso habitual: public public Acceso por defecto: private

Posibles accesos ambiguos ambiguos

240

Ejemplo Sencillo
class A { public: A(){cout<< A ;} A(){cout<<"A";} }; class B { public: B(){cout B(){cout<<"B";} B ;} }; class C : public A, public B { pub c: public: C(){cout<<"C";} }; // Equivalente a: // class C : public A, p p , public B // {public: C() : A (), B () {cout<<"C";}}; void main() { C c; // Resultado:ABC ; }
241

Ejemplos Herencia Mltiple


Ejemplos Ej l
Ventana
VentanaConMenu V t C M
VentanaConMenuYBorde

VentanaConBorde
VentanaConMenuYBorde

Persona
Empleado
EmpleadoCasado (con descuento por ser empleado y estar casado)

PersonaCasada
EmpleadoCasado
242

Herencia Mltiple
Tipos
class Task{ }; class Displayed{ }; class Satellite : public Task, public Displayed { Task }; void highlight(Displayed*); o d g g t( sp ayed ); void suspend(Task*) void g(Satellite *p) g( p) { highlight(p); // es posible dar un Satellite* donde se esperaba un Displayed* suspend(p); // es posible dar un Satellite* donde se esperaba un Task* }

Herencia Mltiple
Funciones virtuales
class Task{ // virtual void pending() = 0; }; class Displayed{ // // virtual void draw() = 0; }; class Satellite : public Task, public Displayed { //.. void pending(); // se sobreescribe Task::pending() void draw(); // se sobreescribe Displayed::draw() };

Llamadas Constructores/Destructores
Los constructores se llaman en el orden en el que se especifican en la herencia Los destructores en orden inverso herencia. inverso.
#include <iostream> using std::cout; class Task{ public: Task() {cout << "Const. Task\n"; } virtual ~Task() {cout << "Dest Task\n ; } Task() Dest. Task\n"; }; class Displayed{ public: Displayed() {cout << "Const Displayed\n ; } Const. Displayed\n"; virtual ~Displayed() {cout << "Dest. Displayed\n"; } }; class Satellite : public Task, public Displayed { public: Satellite() {cout << "Const. Satellite\n"; } virtual ~Satellite() {cout << "Dest. Satellite\n"; } }; void main(){ Satellite * s = new Satellite; delete s; }

Consola Const. Const Task Const. Displayed Const. Satellite Dest. Satellite Dest. Displayed Dest. Task

Ambigedad
Bases con miembros que se llaman igual
class B { public: void g () {} void f(int) {} }; class D { public: void g() {} void f() {} }; class C : public B, public D {}; void main(int argc, char* argv[]) { C c; // c.g(); error: "ambiguous access of g" c.B::g(); // OK // c.f(); error: "ambiguous access of f // Es una especie de ocultacin recproca c.D::f(); c D::f(); // OK }

246

#include <iostream> using std::cout; class A{ public: void f(int) {cout << "A::f(int)\n"; } void f( h ) { id f(char) {cout << "A f( h )\ " } t "A::f(char)\n"; //... }; class B{ l public: void f(double){cout << "B::f(double)\n"; }; //... }; class AB : public A, public B { public: using A f i A::f; using B::f; void f(double) {cout << "AB::f(double)\n"; } void f(char) {cout << "AB::f(char)\n"; } }; } void main(){ AB a; a.f(1); f(1) a.f('a'); a.A::f('b'); }

Ambigedad
Declaraciones using

Consola A::f(int) AB::f(char) A::f(char)

Clases Base Replicadas


Con la herencia mltiple sera posible t C l h i lti l ibl tener una clase base replicada.
Link Link Task Displayed Task Link Displayed Satellite

Satellite

Link estara dos veces en Satellite Satellite.

Clases Base Replicadas p


class Storable{ public: Storable(string *); virtual void read() = 0; virtual void write() = 0; virtual ~Storable(); private: string fileStore; Storable (const Storable&); Storable & operator= (const Storable&); }; } class Transmitter: public virtual Storable { public: void write(); //... // }; class Receiver: public virtual Storable { public: void write(); id it () //... }; class Radio: public Transmitter, public Receiver { public: bli void write(); //... };

Herencia virtual

Storable Transmitter Receiver

Radio

Herencia Virtual
Una herencia virtual para un conjunto de clases hermanas (hij d una clase X) especifica que no se h (hijas de l ifi repliquen las componentes heredadas de X para un j perteneciente a una clase descendiente comn objeto p de las clases hermanas Es adecuado en casos en que la clase base virtual tiene pocos miembros de datos, o ninguno. El constructor de la clase virtual se llama una sola vez, por el constructor de la clase derivada ms abajo en la jerarqua. Permite desambiguacin en acceso a componentes heredadas (ver Ejemplo desambiguacin virtual)

250

Ejemplo Herencia Virtual


template<class _Elem,class _Traits> class basic iostream Elem class Traits> basic_iostream : public basic_istream<_Elem,_Traits>, public basic_ostream<_Elem, _Traits> template<class _Elem,class _Traits>class basic_istream : virtual public basic_ios<_Elem, _Traits> template<class _Elem,class _Traits> class basic_ostream : virtual public basic_ios<_Elem, _Traits> p , typedef basic_iostream<char,char_traits<char>> iostream; typedef basic_istream<char, char traits<char> > istream; basic istream<char char_traits<char> typedef basic_ostream<char, char_traits<char> > ostream; typedef basic_ios<char, char_traits<char> > ios;
251

Ejemplo Herencia Virtual


class A {p blic A() {co t << "A" }} {public: {cout "A";}}; class B : virtual public A {public: B() {cout << "B";}}; class D : virtual public A {public: D() {cout << "D";}}; class E : public A {public: E() {cout << "E";}}; class C: public B, public D, public E {public: C() {cout << "C";}}; void main(int argc, char* argv[]) { C c; // Resultado:ABDAEC // Si ninguna herencia fuera // virtual --> Resultado:ABADAEC }
252

Ejemplo Desambiguacin Virtual


class class class class A {public: int a; void f(){}}; B : public A {}; D : public A {}; C: public B, public D {};

void main() { C c; ; // c.a=7; error: "ambiguous access of a" // c.a=7; correcto si la B y D son // hermanas virtuales hijas de A c.A::a=7; // OK, se cambia el de B::A. c.D::a=8; // OK A a; // A a=c; error: "ambiguous conversions // from C to 'const A &'" // A a=c; correcto si l B y D son i la //hermanas virtuales hijas de A }

253

Herencia Virtual y Mtodos Virtuales


Contexto: C t t
class A {}; class B : virtual public A {}; class D : virtual public A {}; class C: public B, public D {};

Algoritmo de desambiguacin p g g para objeto.mtodo (mtodo virtual)


Entre la clase esttica de objeto y la clase dinmica (que siempre es descendiente de la esttica), se permiten slo overriding en una cadena lineal de clases
254

Ejemplos
Caso 1 C
virtual A::f virtual D::f virtual B::f

Sin herencia virtual: Si h i it l


C c; c.f o B::f) llamada ambigua (no sabe si aplicar D::f
Se podra aadir using D::f en la clase C.

Con herencia virtual:


Error en la declaracin de la clase C:
C: ambiguous inheritance of void A::f
255

Ejemplos
Caso 2 C
virtual A::f virtual D::f

Sin herencia virtual:


C c; c.f llamada ambigua (no sabe si aplicar B::A::f o D::f). Podramos poner en C i D f P d using D::f;

Con herencia virtual:


Dominancia: D::f sobreescribe a A::f C c; c.f(); A & a=c; a.f();
Ejecucin doble de D::f
256

#include <iostream> using std::cout; class Base{ { public: virtual void foo() = 0; virtual void bar() = 0; }; class Der1: public virtual Base{ public: virtual void foo() { () cout << "Der1::foo()\n"; bar(); } // se ejecuta Der2::bar()!}; }; class Der2 : public virtual Base{ public: virtual void bar() { cout << "Der2::bar()\n"; } () () }; class Join: public Der1, public Der2{}; void main(){ (){ Join * p1 = new Join; Der1* p2 = p1; Base* p3 = p1; p1->foo(); p2->foo(); p3->foo(); }

Cross-Delegation Cross Delegation

Consola Der1::foo() Der2::bar() Der1::foo() Der2::bar() Der1::foo() Der2::bar()

Indice
Tipos y D l Ti Declaraciones. i Funciones. Clases. Espacios de Nombres. Biblioteca Estndar (STL). Herencia.

Manejo de Errores.
Errores de ejecucin terminacin del ejecucin, programa. Excepciones. Excepciones Entrada/Salida.

258

Errores de Ejecucin
class A { public: int x; }; class B : public A { public: int y; }; void main(int argc, char* argv[]) { A* p; // p->x=3; error de ejecucin A a; B* q=(B*)&a; // en Java error de ejecucin // q->y=7; error d ejecucin > 7 de j i } Error de ejecucin: El programa finaliza mostrando una ventana de dilogo

259

Finalizacin del Programa


exit(int ) it(i t x)
Finalizacin normal mostrando ventana de comandos
El valor de esta finalizacin es x, que suele ser 0

terminate() terminate()
Finalizacin de un programa mostrando una ventana de dilogo (error de ejecucin) Si una excepcin no se captura o se produce un error de ejecucin, se llama a terminate() No se produce liberacin de memoria automtica Finalizacin anloga haciendo abort() abort()
260

Modificacin de Finalizacin
void funcionTerminacion () { cout << "Finalizando" << endl; exit( -1 ); } void main(int argc, char* argv[]) { set_terminate(funcionTerminacion); throw "error"; error ; cout << "Final del programa" << endl; } Resultado: Finalizando Al producirse un error no se llama a terminate sino a funcionTerminacion Si no ponemos exit(-1) se finalizara mostrando la ventana de dilogo de error
261

Excepciones
Sintaxis de clusulas catch catch catch(tipo variable) o catch(tipo) catch(...)

Incorrecto: catch(... variable) I h( i bl ) Si hay ms catch, el catch(...) debe ser el ltimo Liberacin de memoria Al acceder a parte catch se libera la memoria automtica, pero el programador debe tener en cuenta la liberacin de memoria dinmica Excepciones posibles en una funcin ... funcion (...) throw ([tipo]*) {...} Estas declaraciones se consideran comentarios En algunas versiones de C++, se producen errores de ejecucin al lanzarse excepciones no previstas en la cabecera Si en la cabecera no est la declaracin throw, quiere decir 262 que su cdigo puede lanzar cualquier excepcin

() Algunas inconsistencias (*)


class A { public: virtual void f () {} virtual void g () throw (int) {} }; class B : public A { private: virtual void f () {} public: virtual void g () throw (int, char*) {} }; void main(int argc, char* argv[]) { B b; A & a=b; // b f() b.f(); error, porque B f es privado B::f i d a.f(); // (*) acceso al mtodo privado B::f a.g(); // (*) acceso al mtodo B::g, que puede // lanzar mas excepciones que A::g } // (*) Inconsistencias eliminadas en Java

263

Otros Errores
Memoria di i agotada M i dinmica t d
Se lanza una excepcin de la clase bad_alloc Dos D modos d respuesta ( l d de (alternativos) i )
Atrapar la excepcin Modificar la respuesta por defecto (forma anloga a set_terminate)
set_new_handler(funcionTerminacion);

Uso de aserciones
#include <cassert> assert (x==7); // si es falso, se llama a terminate falso terminate

264

Otros Errores
// bad_alloc.cpp // compile with: /EHsc #include<new> #include<iostream> using namespace std; int main() { char* ptr; try { ptr = new char[(~unsigned int((int)0)/2) - 1]; // 2.147.483.646 bytes delete[] ptr; } catch( bad alloc &ba) { bad_alloc cout << ba.what( ) << endl; } }

Excepciones en MFC
Clases CException, CArchiveException, etc Macros TRY y CATCH. Estas macros slo funcionan con excepciones f i i que heredan de CException. Evitan tener que borrar un puntero a la excepcin (pEx->Delete).

CFile* pFile = NULL; try { pFile = new CFile(_T("C:\\WINDOWS\\SYSTEM.INI"), CFile::modeRead | CFile::shareDenyNone); C C ) DWORD dwLength = pFile->GetLength(); CString str; str.Format(_T("Your SYSTEM.INI file is %u bytes long."), dwLength); d L h) AfxMessageBox(str); } catch(CFileException* pEx) { pEx->ReportError(); E R tE () pEx->Delete(); } catch(CMemoryException* pEx) { // We can't recover from this memory exception, so we'll W 't f thi ti 'll // just terminate the app without any cleanup. Normally, an // an application should do everything it possibly can to // clean up properly and _not_ call AfxAbort(). pEx->Delete(); E D l t () AfxAbort(); } // If an exception occurrs i th CFil constructor, ti in the CFile t t // the language will free the memory allocated by new // and will not complete the assignment to pFile. // Thus, our clean-up code needs to test for NULL. if ( Fil ! NULL) { (pFile != pFile->Close(); delete pFile; }

266

CFile CFile* pFile = NULL; TRY { pFile = new CFile( _T( "C:\\WINDOWS\\SYSTEM.INI" ), CFile::modeRead | CFile::shareDenyNone ); ULONGLONG dwLength = pFile->GetLength( ); CString str; str.Format( _T( "Your SYSTEM.INI file is %I64u bytes long.") , dwLength ); AfxMessageBox( str ); } CATCH( CFileException, pEx ) { // Simply show an error message to the user user. pEx->ReportError(); } AND_CATCH(CMemoryException, pEx) { AfxAbort( ); } END_CATCH // If an exception occurs in the CFile constructor constructor, // the language will free the memory allocated by new // and will not complete the assignment to pFile. // Thus, our cleanup code needs to test for NULL. if ( pFile ! NULL ) { != pFile->Close( ); delete pFile; }

Excepciones en MFC

Indice
Tipos y Declaraciones. p Funciones. Clases. Clases Espacios de Nombres. Biblioteca Estndar (STL) (STL). Herencia. Manejo d E M j de Errores.

Entrada/Salida.
Formato de E/S. Ficheros. Ficheros Corrientes de caracteres

268

Formato de Entrada/Salida
Indicadores
cout.setf (ios::showpos); // nmeros >=0 con + cout << "Numero:" << 1; // Numero:+1 cout << "Numero:" << 2; // Numero:+2 cout.unsetf(ios::showpos); cout << "Numero:" << 1; // Numero:+1 Numero: cout << "Numero:" << 2; // Numero:+2

Manipuladores
cout << << // // << // << // oct << "Numero1:" << 23 << ",Numero2:" 1 2 dec << 44; el 23 en octal y el 44 en decimal Numero1:27,Numero2:44 u e o , u e o oct << "Numero:" << 88; Numero:130 "Numero:" << 88; N Numero:130 130
269

cout cout

El manipulador endl inserta un salto de lnea

Formato de Entrada/Salida
Dos lt D alternativas: i di d ti indicadores o manipuladores. i l d Ejemplo de uso equivalente (resultado: ###23): ###23 ):
// Uso 1
cout.width(5); // afecta slo a la prxima llamada de "<<" cout.fill('#'); // afecta a las prximas llamadas de "<<" cout << 23 << endl; // Uso 2 cout << setw(5) << setfill('#') << 23 << endl; // necesario #include <iomanip> p // afecta slo a prxima llamada de <<
270

Formato de Entrada/Salida
Otros ejemplos (nmeros reales): Ot j l ( l )
cout << 1234.56789 << endl; // lit literales o variables d bl l i bl double // Resultado:"1234.57 ( ) (' ) cout << setw(5) << left << setfill ( _') << -23 << endl; // Resultado:"-23__" cout << scientific << 1234.56789 << endl; // Resultado:"1.234568e+003" cout << fixed << 1234 56789 << endl; 1234.56789 // Resultado:"1234.567890" // Siempre con 6 cifras decimales
271

Miembros de <iomanip>
resetiosflags: Borra los flags que se especifiquen. setbase: Establece la base para enteros. setfill: Establece el carcter que se usar para rellenar espacios en el caso de justificado a la derecha. setiosflags: E t bl ti fl Establece l fl los flags que se especifiquen. ifi setprecision: Establece la precisin para valores en punto flotante. flotante setw: Establece el ancho.

272

ios_base::fmtflags ios base::fmtflags


namespace s d { a espace std class ios_base { public: typedef implementation-defined-bitmask-type fmtflags; static const fmtflags boolalpha; static const fmtflags dec; t ti t f tfl d static const fmtflags fixed; static const fmtflags hex; static const fmtflags internal; g ; static const fmtflags left; static const fmtflags oct; static const fmtflags right; static const fmtflags scientific; t ti t f tfl i tifi static const fmtflags showbase; static const fmtflags showpoint; static const fmtflags showpos; g p ; static const fmtflags skipws; static const fmtflags unitbuf; static const fmtflags uppercase; static const fmtflags adjustfield; static const fmtflags basefield; static const fmtflags floatfield; ... }; }

273

#include "stdafx.h" // output_stream_manip.cpp // compile with: /GR /EHsc #include <i t #i l d <iostream> > #include <iomanip> using namespace std;

Formato de Entrada/Salida o ato t ada/Sa da


Manipuladores definidos por el usuario

void fb( ios_base& os, int l ) { ostream *pos = dynamic_cast<ostream*>(&os); if (pos) { for( int i=0; i < l; i++ ) i 0 l (*pos) << ' '; }; } _Smanip<int> __cdecl fillblank(int no) { return (_Smanip<int>(&fb, no)); } int main( ) { cout << "10 blanks follow" << fillblank( 10 ) << ".\n"; }

Ficheros
Lectura/Escritura. T t /Bi i L t /E it Texto/Binarios. Distintos modos de apertura. Ejemplo:
p.open(plano.txt, i ( l ios::app); ) p << abc; // aadir datos al // fichero existente

Ficheros binarios
Mecanismo de serializacin en casos sencillos
Objetos sin atributos punteros
P Para objetos con variables puntero, se guarda una posicin d bj i bl d i i de memoria sin sentido

En Java, la serializacin est permitida p p para objetos

275

Ejemplo Ficheros Binarios


int x=123456; int y=987654; x 123456; y 987654; cout << "Int:" << sizeof x << endl; // Int:4 // Alternativa: sizeof (int) ofstream f ("datos.bin", ios::binary); f.write((char*) &x, sizeof x); f.write((char ) f.write((char*) &y, sizeof x); f.close(); // Tamao del fichero datos.bin: 8 bytes x=0; y=0; ifstream g ("datos.bin", ios::binary); g.read((char ) g.read((char*) &x, sizeof x); g.read((char*) &y, sizeof x); g.close(); cout << "X:" << x << endl; // X:123456 // Y:987654 cout << "Y:" << y << endl;
276

Mscaras de apertura
app, al fin del stream antes de cada insercin. ate, al fin del stream cuando se crea. binary, para leer un fichero como un stream binario, en vez de un stream de texto texto. in, para permitir extraccin de un stream. out, para p ,p permitir insercin de un stream. trunc, para borrar el contenido de un fichero existente cuando el objeto se crea.
#include <iostream> #include <fstream> int main ( ) { using namespace std; fstream file; file.open( "rm.txt", ios_base::out | ios_base::trunc ); file << "testing"; }

277

Corrientes de Caracteres
Lectura/Escritura de corrientes de caracteres Clase stringstream en <sstream>. Alternativa (menos estndar): Clase strstream en <strstream> tiles en conversiones de tipo (alternativas a atof, atoi, itoa, etc). Ejemplos:
#include <sstream> using namespace std; // Ejemplo 1 string numComoStr1 (double x) { stringstream f; string s; f << x; f >> s; return s; } // Ejemplo 2 string numComoStr2 (double x) { ostringstream u; u << x; return u.str(); }

278

Manejo de Errores
Errores en manipulacin d fi h E i l i de ficheros
Abrir un fichero que no existe, etc Por defecto estas operaciones no lanzan excepciones

Ejemplo:
ifstream is; ; char* fichero = "plano.txt"; is.open ( p (fichero); ) if (!is) throw "Error de apertura"; // llamada a is.operator!() p
279

Recursos C++ en la web


Lenguaje C++
http://www.cplusplus.com/doc/tutorial/ p p p http://c.conclase.net/curso/index.php http://www.parashift.com/c++-faq-lite/index.html http://www parashift com/c++ faq lite/index html

Visual Studio 2005


http://www.microsoft.com/spanish/msdn/vs2005 /default.mspx

280

También podría gustarte