Documentos de Académico
Documentos de Profesional
Documentos de Cultura
6 Continuacion C++
6 Continuacion C++
Tema 5
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;
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; , , ,
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
Variable global
Visible en un fichero desde el lugar en que se declara hasta final de fichero.
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
11
Estructuras
Inicializacin
Estructuras
Equivalencia
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 aritmticos: p
*, / (entre enteros se devuelve un entero) % (resto de la divisin)
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
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
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)
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 = № ( l (p= incorrecto, *p= ok) i t * k)
Puntero a constante:
const long * p = № (*p= incorrecto, p= ok)
Array constante:
const int nums[3]={1,2,3}; (nums[1]= incorrecto)
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.
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
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 ; }
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:
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.
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.
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
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
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); }
44
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); }
45
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); }
46
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.
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
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?
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?
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?
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); }
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?
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?
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 &'
#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;
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
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.
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)
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 }
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
#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
75
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
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 ; }
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
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
84
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;
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
Indice
Tipos y Declaraciones. Funciones. F i Clases. Espacios de Nombres. p
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>
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>,
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, > {};
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
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
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); }
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.
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
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
Significado
Significado
Constructor por defecto, crea un contenedor vaco.
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
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
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]
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,
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
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;
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
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.
// 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;
// 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
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()
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
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
163
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
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
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(); }
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.
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?
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
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
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
Tipo polimrfico:
Tiene o hereda mtodos virtuales
Hacer #include <typeinfo> Para tipos no polimrficos, devuelve tipos estticos polimrficos
185
//prints "class Base *" class //prints "class Derived" //prints "class Derived *" //prints "class Derived"
186
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
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
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){} };
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)
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)
Mtodos no virtuales:
Se puede tener 2 definiciones incompatibles
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); }
Consola
209
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 };
... ...
Circle* Circle::clone() const { return new Circle(*this); } Circle* Circle::create() const { return new Circle(); }
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; };
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
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), ==, !=, >, <, >=, <=, &&, ||, ,
No sobrecargables
., ::, ? : . , :: , ? :
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 [ ]
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"; }
#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
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
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
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
Satellite
Herencia virtual
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
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
Ejemplos
Caso 1 C
virtual A::f virtual D::f virtual B::f
Ejemplos
Caso 2 C
virtual A::f virtual D::f
#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(); }
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
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
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
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
273
#include "stdafx.h" // output_stream_manip.cpp // compile with: /GR /EHsc #include <i t #i l d <iostream> > #include <iomanip> using namespace std;
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
275
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
280