6 Continuacion C++

280
C++ Avanzado Tema 5 TACC II 1 TACC II Curso 2008/09 1

Transcript of 6 Continuacion C++

Page 1: 6 Continuacion C++

C++ Avanzado

Tema 5

TACC II111

TACC IICurso 2008/091

Page 2: 6 Continuacion C++

IndiceIndiceTipos y Declaraciones.

DeclaracionesDeclaraciones.Tipos.Operadores.Conversiones de tipos básicos.Instrucciones C++.Constantes.Constantes.Gestión de memoria.

Funciones.ClClases.Espacios de Nombres.Biblioteca Estándar (STL).( )Herencia.Manejo de Errores.E t d /S lid

222

Entrada/Salida.2

Page 3: 6 Continuacion C++

Declaración de VariablesDeclaración de VariablesDeclaración vs. Definición

En C++ antes de usar un nombre (un identificador) hay que declararloEn C++ antes de usar un nombre (un identificador) hay que declararlo (especificar su tipo).

char ch;i 3 926const double pi = 3.141592654;

double sqrt(double);struct User;t t D t {i t d }struct Date {int d, m, y; };extern int error_number;

Algunas declaraciones pueden ser además definiciones (definen una entidad para el identificador):

char ch; // def.: cantidad de memoriad bl i //const double pi = ...; // def.: valor.

double sqrt(double); // no def.struct User; // no def.str ct Date {int d m } // def n e o tipo

333

struct Date {int d, m, y;};// def.: nuevo tipo.extern int error_number; // no def. 3

Page 4: 6 Continuacion C++

Declaración de VariablesDeclaración de VariablesDeclaración vs. Definición

Debe haber exactamente una definición por cada declaración.

Puede haber varias declaraciones, que deben coincidir en el tipo de la entidad a la que se refierenel tipo de la entidad a la que se refieren.

int count;

int count; // error: redefinicion

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

4444

Page 5: 6 Continuacion C++

Estructura de una Declaración

C t d t t

Estructura de una Declaración

Consta de cuatro partes:Un especificador opcional (ej.: virtual, extern, static, volatile)Un tipo base (ej.: char, int).Un declarador. Consta de un nombre y opcionalmente unos operadores:

* puntero, prefijo.p p j*const puntero constante, prefijo.& referencia, prefijo.[] array postfijo.[] array postfijo.() función postfijo.

Un inicializador opcional.Excepto funciones y espacios de nombres una declaración terminaExcepto funciones y espacios de nombres, una declaración termina en punto y coma.

char * beers[]={“mahou”, “franciscaner”, “kostritzer”};// tipo base: char

555

// tipo base: char// declarador: * beers[]// inicializador: {“mahou”, “franciscaner”, “kostritzer”}; 5

Page 6: 6 Continuacion C++

EjerciciosEjercicios¿Cómo se declaran e incializan…?

SSea:int f(); int g();int a=1, b=2, c=3, &d=c;, , ,

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

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

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

y

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

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

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

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

Page 7: 6 Continuacion C++

Ámbito de una Declaración

E C d l ió d i bl l l d

Ámbito de una Declaración

En C++ una declaración de una variable local se puede hacer en cualquier lugar de un bloque y es válida hasta el final del mismo.

En C se debe hacer al inicio del bloque.

En sub-bloques se pueden definir variables locales con el mismo nombre (acceso con operador “::” explicadoel 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.

7777

Page 8: 6 Continuacion C++

Ámbito de una DeclaraciónEjemplo

#include <iostream>

char c = 'A'; // c global, declarada fuera de main

void main ( ) {

char c = 'B'; // c local a main{

char c = 'D'; // c local al bloque internostd::cout << c; // c es la c local al b. i.std::cout << ::c; // ::c es la c globalstd::cout << ::c; // ::c es la c global

}}

888

Page 9: 6 Continuacion C++

Ámbito de una Declaración

Ot d “ t ti ”

Ámbito de una Declaración

Otros usos de “static”Variable local de una función

C l i ll dConserva su valor en sucesivas llamadas.Variable global

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

Variable global externa (“extern”)En un fichero se define (opcionalmente un valor):

int numero [= valor];En otro fichero se declara (se utiliza) :

t i t999

extern int numero;9

Page 10: 6 Continuacion C++

Tipos BásicosTipos Básicos

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

ArraysUna variable “const” puede ser la dimensión de un array como memoria estática (incorrecto en C)

La dimensión de un array con memoria dinámica puedeLa dimensión de un array con memoria dinámica puede ser cualquier expresión

10101010

Page 11: 6 Continuacion C++

Enumeraciones estructuras y uniones

enum Color {verde 0 amarillo 2 rojo};

Enumeraciones, estructuras y uniones

enum Color {verde=0, amarillo=2, rojo};enum Color semáforo;Color semaforo; //(incorrecto en C)

union Numero {long x; char y;char y;

};

union Numero n; ;Numero n; //(incorrecto en C)

struct Libro {. . .}; struct Libro novela;Libro novela; //(incorrecto en C)

11111111

Page 12: 6 Continuacion C++

EstructurasInicialización

Se pueden inicializar con el mismo estilo que un array.

struct address{{

char * name;long int number;h t t [2]char state[2];

long zip;};

address jd = {"Jim Dandy", 61, {'N', 'J'}, 8899};

12121212

Page 13: 6 Continuacion C++

Estructuras

S di ti t ti t l i

Equivalencia

Son distintos tipos aunque tengan los mismos miembros.

struct S1struct S1{

int a;};};

struct S2{{

int a;};

void main(){

S1 x;

131313

;S2 y = x; // error

} 13

Page 14: 6 Continuacion C++

OperadoresOperadores

Operadores lógicos :Operadores lógicos : ! (negación), &&, ||

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

Operadores de comparación: ==, !=Operadores con 1 argumento (usar argumentos con o p g ( gsin paréntesis):

sizeofreturnreturndelete

Operadores aritméticos:p*, / (entre enteros se devuelve un entero)% (resto de la división)

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

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

Page 15: 6 Continuacion C++

Operadores

Operador de expresión condicional:

Operadores

Operador de expresión condicional: valor = (x<0) ? x : -x; (condición entre paréntesis)

Cada operador tiene definida una asociatividad (izquierda-derecha o derecha-izquierda). Ejemplo:+ b + 3 equivale a + (b + 3)a += b += 3; equivale a a += (b += 3);

cout << “a = “<<a; equivale a (cout << “a = “) << a;

Para expresiones con varios operadores, C++ coloca paréntesis de acuerdo a (ver tablas siguientes):

Prioridad entre operadores (decreciente verticalmente yPrioridad entre operadores (decreciente verticalmente y equivalente horizontalmente)Asociatividad de operadores

15151515

Page 16: 6 Continuacion C++

OperadoresOperadoresPrioridad (decreciente)

16161616

Page 17: 6 Continuacion C++

OperadoresOperadoresPrioridad (decreciente)

17171717

Page 18: 6 Continuacion C++

Conversiones de tipo (i)p ( )Para tipos predefinidos

Es aconsejable evitar castings explícitos son fuente deEs aconsejable evitar castings explícitos, son fuente de errores.En C++ muchos castings son innecesarios en situaciones

i t 3

gdonde sí lo eran en C.Evitar los castings al estilo de C:

int x=3;double y=3.4;x=y; // warningx=(int)y; // no recomendado en C++

Notación “funcional”: x=int(y);Para tipos predefinidos es equivalente a: x=(int)y;La notación T() devuelve el valor por defecto para el tipo

( f )181818

T: int j=int(); (útil cuando se definen templates).18

Page 19: 6 Continuacion C++

Conversiones de tipo (ii)p ( )Para tipos predefinidos

Castings al estilo C++:Operador static_cast: convierte entre dos tipos relacionados (ej.: punteros en la misma jerarquía de herencia, entero a enumerado, punto flotante a entero)

int x = 3;

O d i t t t i t t d ti i

int x = 3;double y = 4.5;x = static_cast<int>(y); // x vale 4

Operador reinterpret_cast: convierte entre dos tipos sin relación: double* x = reinterpret_cast<double *>(3);Operador dynamic cast: conversión controlada enOperador dynamic_cast: conversión controlada en tiempo de ejecución.Operador const cast: para quitar los calificadores const

191919

Operador const_cast: para quitar los calificadores consty volatile a punteros. 19

Page 20: 6 Continuacion C++

Instrucciones C++Instrucciones C++Declaraciones.

Es aconsejable inicializar las variables a la vez que se declaran, para evitar llamar a constructores innecesariamente.I t d i l i bl l á bit iblIntroducir las variables en el menor ámbito posible.

Instrucciones de selección:if (condition) statementif (condition) statementif (condition) statement else statementswitch (condition) statement( )

Los operadores de comparación: ==,!=,<,<=,>,>= devuelven bool(true) si la comparación es verdadera y bool(false) si es falsa.L d ló i && || lú d tLos operadores lógicos &&, || no evalúan su segundo argumento a menos que sea necesario.Es posible declarar variables en condicionales:

202020

pif (double d=prim(true)) left/=d; 20

Page 21: 6 Continuacion C++

Instrucciones C++Instrucciones C++

Instrucciones de iteración:while (condition) statementdo statement while (expression);do statement while (expression);for (for-init-statement conditionopt; expressionopt)

Se pueden declarar variables en el for:void f(int v[], int max){

for (int i=0; i<max; i++) v[i] = i*i; // el ámbito de i es el bloque forfor (int i 0; i max; i ) v[i] i i; // el ámbito de i es el bloque for}

Goto: no usar!goto identifier;identifier: statement

212121

identifier: statement21

Page 22: 6 Continuacion C++

ConstantesConstantesUna variable tipo “const” necesita un valor inicialUna variable tipo const necesita un valor inicialTipos primitivos no punteros:const int x = 3;

7 // d il ióx=7; // error de compilaciónObjetos:

Observación: “const Punto p;” es válido (se considera que “Punto p;” está dando un valor inicial con constructor vacío)p; está dando un valor inicial con constructor vacío)const Punto p1(3,4); Punto p2(5,6); p1=p2; //incorrecto; p1.x=33; // incorrectop1 p2; //incorrecto; p1.x 33; // incorrecto

Literales de caracteres: char * p = “casa”; p[0]=‘u’; // error de ejecuciónp[0] u ; // error de ejecuciónchar cad [] = “casa”; cad[0]=‘u’; // válido porque cad es una copia del literal

222222Si aparece “casa” varias veces, Visual C++ crea un solo hueco de memoria para este literal, aunque es dependiente de la implementación.22

Page 23: 6 Continuacion C++

ConstantesConstantes

Punteros:Puntero constante:

l * (“ ” i t “* ” k)long * const p = &numero; (“p=…” incorrecto, “*p=…” ok) Puntero a constante:

const long * p = &numero; (“*p=…” incorrecto, “p=…” ok)Array constante:

const int nums[3]={1,2,3}; (“nums[1]=…” incorrecto)Puntero a objeto constante:j

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

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

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

23232323

const Punto p1(3,4); Punto & p2 =p1; // incorrecto

Page 24: 6 Continuacion C++

Gestión de MemoriaGestión de Memoria

C: malloc freeC: malloc, freeC++:

Variablesint * p1 = new int; // tipos primitivosPunto* p2 = new Punto (3,4);Punto* p3 = new Punto (); Punto* p4 = new Punto; // constructor vaciodelete p1; delete p2; …

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

El uso de “delete” para memoria no dinámica produce un error de ejecuciónSe debe usar “delete” o “delete []” convenientemente

24242424

Se debe usar delete o delete [] convenientemente (según se aplique a un array o no)

Page 25: 6 Continuacion C++

IndiceIndiceTipos y Declaraciones.p yFunciones.ClClases.Espacios de Nombres.pBiblioteca Estándar (STL).HerenciaHerencia.Manejo de Errores.Entrada/Salida.

25252525

Page 26: 6 Continuacion C++

FuncionesFunciones

Una función no se puede llamar a no ser que se haya declarado previamente.L d l ió d f ió h d ifiLa declaración de una función ha de especificar: su nombre, el tipo devuelto, el número y tipo de sus argumentosargumentos.La semántica del paso de argumentos es igual a la de inicialización.c a ac óUna definición es una declaración donde se incluye el cuerpo de la función.pLas funciones han de definirse exactamente una vez.

26262626

Page 27: 6 Continuacion C++

FuncionesFuncionesDefinición.

L d fi i ió d f ió d llLa definición de una función puede llevar: “extern” (disponible para otros archivos). Valor por defectodefecto.“static” (no disponible para otros archivos)

Sobrecarga: En C++ puede haber más de unaSobrecarga: En C++ puede haber más de una definición para el mismo nombre de función (no en C).en C).Observación: El “estilo antiguo” de declaración de funciones de C no es válido en C++:de funciones de C no es válido en C :

double media (datos, dim) double * datos; long dim

27272727

; g{ …}

Page 28: 6 Continuacion C++

FuncionesFuncionesArgumentos.

Argumentos opcionales:Argumentos opcionales:Argumentos = (…, tipo variable = valor-defecto, …)Para evitar ambigüedades, detrás de un argumento opcional no

d i t lpueden ir otros que no lo seanNúmero variable de argumentos (válido también en C):

“void dibujar (int x, int y, …)” j ( , y, )Llamadas posibles:

• dibujar(3); // error • dibujar(3,4); // y={4}

dib j (3 4 5) // {4 5}• dibujar(3,4,5); // y={4,5}La cabecera “<cstdarg>” (<stdarg.h> en C) contiene macros para acceder a los elementos de “y” (en el ejemplo anterior) Un ejemplo: “printf”Un ejemplo: printfEquivalente: “void dibujar (int x, int y …)”

28282828

Page 29: 6 Continuacion C++

Ejemplo#include <iostream>

EjemploArgumentos por defecto.

using std::cout;using std::endl;

double potencia (long base, long exponente = 2){

if (exponente == 2) return (base * base);elseelse {

double res = base;for (long i=1; i<exponente; i++)( g ; p ; )

res *= base;return res;

}}}

void main(){

292929

{cout << "potencia (3) = " << potencia (3) << endl;cout << "potencia (3, 4) = " << potencia (3, 4) << endl;

}

Page 30: 6 Continuacion C++

Funciones

#include <iostream>

FuncionesArgumentos 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);if (severity) exit(severity);

}

void main(){

30303030

{error(1, "error", "muy", "severo", 0);

}

Page 31: 6 Continuacion C++

Funciones

D l ió ( j l )

FuncionesPunteros a Funciones

Declaración (ejemplo): int (* funcion) (int x); i t (* f i ) (i t )int (* funcion) (int );

Asignación:f ifuncion=g;funcion=&g;

Ll dLlamada:funcion(3);(*f i )(3)(*funcion)(3);

¿Cómo se declara un array de punteros a funciones?

31313131int ( ** func ) (int) = new (int (*[7])(int));int ( * func2 [4]) (int);

Page 32: 6 Continuacion C++

Funciones

int h(int ) {

FuncionesPunteros a Funciones. Ejemplo.

int h(int x) {return 4;

}int g (int n, int (*f) (int)) {

int u = f(3); // también válido (*f)(3)return u;

}int k=g(5, h); //también válido “g(5,&h);”

32323232

Page 33: 6 Continuacion C++

PreprocesadorPreprocesador

#define DIM 20#define curva(a) 1+2*a+a*a

Alternativa a funciones “inline”inline double curva (double a) {

return 1+2*a+a*a ;}

Siempre es preferible el uso de funciones inline.Inclusión condicional:Inclusión condicional:

#ifndef, #if, #else, …#pragma once

33333333

#pragma once

Page 34: 6 Continuacion C++

Biblioteca Estándar de CBiblioteca Estándar de C<assert h> (macro assert )<assert.h> (macro assert, …)<ctype.h> (comprobaciones de tipo)<errno.h> (errores de fuera de rango de números, …)<float.h> (constantes para los números reales: valor máximo del tipo double, …)<limits.h> (tamaño de los enteros short, …)<locale.h> (adaptaciones al idioma)<math.h> (funciones matemática:sin, cos, …)<setjmp h> (saltarse niveles de ejecución)<setjmp.h> (saltarse niveles de ejecución) <stdarg.h> (acceso a los argumentos de una función 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 conversión de números y reserva dinámica de memoria: atof, atoi, _itoa, malloc, free, …) <signal.h> (señales de interrupción externa)<string.h> (strcmp, strcpy, strlen, …)g<time.h> Reemplazadas por <cnombre-cabecera> en C++ (ej.: <cstdio>, etc.), las funciones se hacen accesibles desde el espacio de nombres std:

#include <cstdio>34343434

#include <cstdio>using std::printf;

Page 35: 6 Continuacion C++

IndiceIndiceTipos y Declaraciones.F iFunciones.Clases.

D fi i ióDefinición.Atributos e inicialización.EncapsulamientoEncapsulamiento.Constantes.Tipos InternosTipos Internos.Castings

Espacios de NombresEspacios de Nombres.Biblioteca Estándar (STL).Herencia.

353535Manejo de Errores.Entrada/Salida.

35

Page 36: 6 Continuacion C++

Clases

Definición de clase:

ClasesDefinición.

Definición de clase: class NombreClase { …};

Debe acabar en “;“ (es obligatorio también en estructuras y en prototipos de métodos dentro de la clase)prototipos de métodos dentro de la clase)

Para cualquier clase X se supone que existen por defecto las siguientes definiciones:siguientes definiciones:

Un constructor vacío“X::X()”Llamada implícita al constructor vacío de clases padre y al constructorLlamada implícita al constructor vacío de clases padre y al constructor vacío para sus elementos que sean objetosAl sobrecargarlo, desaparece esta definición por defecto

Un constructor especial (constructor de copia) que llama recursivamente al constructor de copia para sus elementos

“X::X(const X &)”

36363636

( )Una llamada explícita al constructor de copia se puede poner como un “casting”

Page 37: 6 Continuacion C++

Clases

U d t t ( ódi í )

ClasesDefinición.

Un destructor (código vacío)• “X::~X()”• Al destruir un objeto (para los casos de memoriaAl destruir un objeto (para los casos de memoria

automática o en llamadas a “delete” para memoria dinámica), se llama al destructor del objeto y después se destruyen las variables del objetodestruyen las variables del objeto

El operador asignación “=“, que por defecto p g q pllama al operador “=“ para los elementos del objeto

“X t ( t X & )”“X::operator=(const X & x)”“X::operator=(const otroTipo & t)”“operator=(tipoPrimitivo, tipoPrimitivo)” no es válido

373737

p ( p , p )

Page 38: 6 Continuacion C++

Clases#include <iostream>

ClasesEjemplo definición por defecto.

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 defectoRect r, r2; // llamada 2 constructores vaciosr.setX(10).setY(20);Rect r1 = r; // llamada constructor copia

383838

r2 = r1; // operador asignación// llamada tres destructores

}

Page 39: 6 Continuacion C++

class Rect{

static int max_data;double x y;

ClasesEjemplo definicióndouble x, y;

int * data;public:

Rect(double cx = 0, double cy = 0) : x(cx), y(cy), data(new int[max_data]) {}

Ejemplo definición.

( y ) ( ) y( y) ( [ _ ]) {}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 haría this->data = r.data, cosa que no queremos~Rect() { delete [] data; }~Rect() { delete [] data; }Rect & operator= (Rect & r2 ) {

x=r2.x;y=r2.y;y ysetData(r2.getData());return * this;

}double getX() const { return x; }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;

393939

return this;}

};int Rect::max_data = 10;

Page 40: 6 Continuacion C++

Clases

Se declaran mediante:

ClasesAtributos.

Se declaran mediante:“tipo variable;” (sin dar un valor inicial)

La variable tomará un valor al llamar a un constructor de laLa 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 ll í l t t di t i l i bl bj tllamaría al constructor correspondiente si la variable es un objeto

• En caso contrario, si la variable es un objeto, se llamaría al constructor vacío para “tipo”

Si aparece “this->variable=valor” en el código del constructor se produciría también 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.

404040

g

Page 41: 6 Continuacion C++

Clases

P d f i d t t

ClasesAtributos.

Pueden ser referenciadas en constructores o métodos mediante:

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

Observación: la siguiente instrucción es válidaObservación: la siguiente instrucción es válida “this->x=x;” (si x es variable de objeto y también una variable local de un constructor o método)

414141

)

Page 42: 6 Continuacion C++

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

class Persona{string nombre;

ClasesInicialización Atributos Objetos. Ejemplo (i).

string nombre;int edad;

public:Persona(string n="Fernando", int e=18) {

nombre = n; edad = e;nombre = n; edad = e;cout << "Constructor “;mostrar();

}void mostrar() { cout << "Persona::" << nombre << ", edad " << edad << "\n“; }

};};

class Empresa {Persona jefe;string nombre;string nombre;

public:Empresa(Persona j, string n) { nombre = n; jefe = j; }void mostrar() { cout << "Empresa::" << nombre << "\n“ << "Jefe::";

jefe mostrar();jefe.mostrar();}

};

void main() {Constructor Persona::Luis, edad 33Constructor Persona::Fernando edad 18

Salida

42

void main() { Persona p("Luis", 33); Empresa e(p, "Google");e.mostrar();

}

Constructor Persona::Fernando, edad 18Empresa::GoogleJefe::Persona::Luis, edad 33

Page 43: 6 Continuacion C++

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

class Persona {string nombre;

ClasesInicialización Atributos Objetos. Ejemplo (ii).

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() { C t t P L i d d 33Salida

43

Persona p("Luis", 33);Empresa e(p, "Google");e.mostrar();

}

Constructor Persona::Luis, edad 33Empresa::GoogleJefe::Persona::Luis, edad 33

Page 44: 6 Continuacion C++

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

class P{protected:

ClasesInicialización Atributos. Ejemplo (i).

protected:int x;

public:P(int a=0) : x(a) {{

cout << "Constructor ";show();

} Constructor P {x=3}C t t H { 2}

Salida

void show() { cout << "P {x=" << this->x <<"}\n"; }};class H : public P{

Constructor H, {x=2}P {x=5}

{int x;

public:H(int b) : x(b), P(b+1){{

P::x += this->x;cout << "Constructor H, {x=" << this->x <<"}\n";show();

}444444

}};void main() { H p(2); }

Page 45: 6 Continuacion C++

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

class P{protected:

ClasesInicialización Atributos. Ejemplo (ii).

protected:int x;

public:P(int a=0) : x(a) {{

cout << "Constructor ";show();

}

SalidaConstructor P {x=0}Constructor H {x=2}void show() { cout << "P {x=" << this->x <<"}\n"; }

};class H : public P{

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

{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();

}454545

}};void main() { H p(2); }

Page 46: 6 Continuacion C++

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

class P{protected:

ClasesInicialización Atributos. Ejemplo (iii).

protected:int x;

public:P(int a=0) : x(a) {{

cout << "Constructor ";show();

}

Salida

Constructor P {x=-858993459}C t t H { 2}void show() { cout << "P {x=" << this->x <<"}\n"; }

};class H : public P{

Constructor H, {x=2}P {x=-858993457}

{int x;

public:H(int b) : x(b), P(x+1){

¡Primero se llama al constructorde la clase base!{

P::x += this->x;cout << "Constructor H, {x=" << this->x <<"}\n";show();

}464646

}};void main() { H p(2); }

Page 47: 6 Continuacion C++

#include <iostream>using std::cout; Clasesclass P{protected:

ClasesInicialización Atributos. Ejemplo (iv).

int x;public:

P(int a=0) : x(a) {{

cout << "Constructor ";show();

}void show() { cout << "P {x=" << this->x <<"}\n"; }

Salida

Constructor P {x=3}C t t H { 858993460 2}void show() { cout << P {x << this >x << }\n ; }

};class H : public P{

int x;

Constructor H, {x=-858993460 y=2}P {x=-858993457}

int x;int y;

public:H(int b) : y(b), x(y), P(b+1)

¡Los atributos se inicializan atendiendo al orden de su declaración!

{P::x += this->x;cout << "Constructor H, {x=" << this->x << “ y=”<<y <<"}\n";show();

474747

();}

};void main() { H p(2); }

Page 48: 6 Continuacion C++

#include <iostream>using std::cout; Clasesclass P{protected:

ClasesInicialización Atributos. Ejemplo (v).

int x, z;public:

P(int a=0) : x(a), z(a+1){{

cout << "Constructor ";show();

}void show() { cout << "P {x=" << this->x <<"}\n"; }void show() { cout << P {x << this >x << }\n ; }

};class H : public P{

int x;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();

484848

();}

};void main() { H p(2); }

Page 49: 6 Continuacion C++

Clases

Declaraciones “public:” “private:” “protected:”:

ClasesEncapsulamiento.

Declaraciones “public:”, “private:”, “protected:”:Pueden afectar a varias declaracionesPuede haber, por ejemplo, varios “private:” (al estilo de Java)j ( )Por defecto es “private:” (en un struct, por defecto es public).Constructores y destructores suelen ser públicos (a no ser que no queramos exponer un determinado constructor, ej.: el q q p , jde copia).“protected:” descrito más adelante en herencia

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

494949

Page 50: 6 Continuacion C++

ConstConst

V i bl “ t”Variables “const”:Tipos primitivos y objetos

No se puede modificar su valorNo se puede modificar su valorOtras 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

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

Para punteros, un “const” puede hacer referencia a la 505050

p , pvariable puntero al colocar “const” junto a la variable

Page 51: 6 Continuacion C++

ConstConstEjemplo

#include <iostream>using std::cout;

class H{

int x;blipublic:

H(int b) : x(b) { }void setX(int g) {x=g;}

};¿Es correcto?

};

void main(){

H (2) j(4)H p(2), j(4);const H * h = &p;h = &j;h->setX(7);

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

515151

( );}

Page 52: 6 Continuacion C++

ConstConstEjemplo

#include <iostream>using std::cout;

class H{

int x;blipublic:

H(int b) : x(b) { }void setX(int g) {x=g;}

};¿Es correcto?

};

void main(){

H (2) j(4)H p(2), j(4);H * const h = &p;h = &j;h->setX(7);

// error! es puntero constante// ok

525252

( );}

Page 53: 6 Continuacion C++

ConstConstEjemplo

#include <iostream>using std::cout;

class H{

int x;blipublic:

H(int b) : x(b) { }void setX(int g) {x=g;}

};¿Es correcto?

};

void main(){

t H (2) j(4)const H p(2), j(4);H * h = &p;h = &j;h->setX(7);

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

535353

( );}

Page 54: 6 Continuacion C++

ConstDeclaración “const” dentro de código de clases:

Constg

Asignable a los tipos que aparecen en métodos y constructores: argumentos y valor de retornoAl final del prototipo de un método de objeto:

“*this=…”, “this->atributo=…”, incorrectosEjemplo:Ejemplo: double Punto::distancia (const Punto & p) const {

return sqrt(p.x*x+ p.y*y); }

Atributos de objeto de tipo “&” y/o “const”Deben de ser inicializados obligatoriamente en el constructorDeben de ser inicializados obligatoriamente en el constructor de la forma “variable(valor)”Si una variables es “const” entonces deja de estar definido el

545454operador “=“

Page 55: 6 Continuacion C++

ConstConstEjemplo

#include <iostream>using std::cout;

class Hclass H{

int x;public:

H(int b) : x(b) { }( ) ( ) { }void setX(int g) {x=g;}void mostrar() { cout << x; }

}; ¿Es correcto?void main(){

H p(2), j(4);const H * h = &p;p;h = &j;h->mostrar();

}// error! es puntero a const H

55

Page 56: 6 Continuacion C++

ConstConstEjemplo

#include <iostream>using std::cout;

class Hclass H{

int x;public:

H(int b) : x(b) { }( ) ( ) { }void setX(int g) {x=g;}void mostrar() const { cout << x; }

}; ¿Es correcto?void main(){

H p(2), j(4);const H * h = &p;p;h = &j;h->mostrar();

}// OK, llamada a un método const

56

Page 57: 6 Continuacion C++

ConstConstEjemplo

#include <iostream>using std::cout;

class Hclass H{

const int x;public:

H(int b) { x = b;} // error C2758: 'H::x' : must be initialized // i t t b / b i iti li li t( ) { ;}

void mostrar() const { cout << x; }};

void main()¿Es correcto?

// in constructor base/member initializer list

(){

H p(2), j(4);const H * h = &p;h = &j;j;h->mostrar();

}

57

Page 58: 6 Continuacion C++

ConstConstEjemplo

#include <iostream>using std::cout;

class Hclass H{

const int x;public:

H(int b) : x(b) {}( ) ( ) {}void mostrar() const { cout << x; }

};

void main()¿Es correcto?

(){

H p(2), j(4);const H * h = &p;h = &j;j;h->mostrar();

}

58

Page 59: 6 Continuacion C++

using std::cout;class H { Argumentos Constclass H {

int x;public:

H(int b) : x(b) {}void mostrar() const { cout << x; }

Argumentos ConstEjemplo

void mostrar() const { cout x; }void setX(int in) { x = in; }

};class I {

int y; E t ?int y;public:

I(int a=0) : y(a) {}void foo(const H & h) {

h.mostrar();

¿Es correcto?

h.mostrar(); h.setX(y);

}void bar(H & h) {

h.mostrar();

// error C2662: 'H::setX' : cannot convert 'this' // pointer from 'const H' to 'H &'

h.mostrar(); h.setX(y);

}};

void main() {H p(2);const H & h = p;I i;

59

;i.foo(p);i.bar(h);

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

Page 60: 6 Continuacion C++

Tipos Internos a ClasesTipos Internos a Clases

Definiciones internas de clases:Dentro de una clase se puede definir otra clase p(también estructuras, tipos mediante “typedef”, …). )

Se podrían hacer llamadas internas al tipo definido o también a “NombreClase::NuevaClase”También sería posible hacer llamadas externas a “NombreClase::NuevaClase”

No se pueden definir funciones dentro de métodos.

606060

Page 61: 6 Continuacion C++

Tipos Internos a ClasesTipos Internos a ClasesEjemplo clase interna

#include <iostream>using std::cout;class H{

int x;class in{

int c;

Salida

Constructor H {x=2 attr c=2}int c; public:

in ( int d = 0 ) : c(d) {}int getc () { return c; }

Constructor H, {x 2 attr.c 2}

} attr;public:

H(int b) : x(b), attr(b){{

cout << "Constructor H, {x=" << x << " attr.c=" << attr.getc() << "}\n";}

};

616161void main() { H p(2); }

Page 62: 6 Continuacion C++

#include <iostream> Tipos Internos a Clasesusing std::cout;

class H{

Tipos Internos a ClasesEjemplo clase interna

{int x;

public:class in{

int c; public:

in ( int d = 0 ) : c(d) {}int getc () { return c; }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 (2)6262

H p(2); H::in b;

}

Page 63: 6 Continuacion C++

CastingsCastings

Un casting equivale a una llamada a un constructor deUn 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 más aún al estilo C: (Complejo)c.

C++ realiza castings implícitos. Ejemplo:Complejo::Complejo(double x) : x(x), y(0) {}p j p j ( ) ( ) y( ) {}Complejo c1=3; Complejo c2(4); const Complejo& c3=5; // sólo con tipos básicosComplejo & c3=5; // incorrecto

636363

Complejo & c3 5; // incorrecto

Page 64: 6 Continuacion C++

#include <iostream>using std::cout;

class H Castingsclass H{

int x;public:

H(int b) : x(b) {}

CastingsEjemplo

H(int b) : x(b) {}void mostrar() const { cout << x; }void setX(int in) { x = in; }

};class I { E t ?class I {

int y;public:

I(int a=0) : y(a) {}void foo(const H & h) {

¿Es correcto?

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;

64

I i;i.foo(2);i.bar(2);

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

Page 65: 6 Continuacion C++

#include <iostream>using std::cout;

class H Castingsclass H{

int x;public:

H(int b) : x(b) {}

CastingsEjemplo

H(int b) : x(b) {}void mostrar() const { cout << x; }void setX(int in) { x = in; }

};class I { E t ?class I {

int y;public:

I(int a=0) : y(a) {}void foo(const H & h) {

¿Es correcto?

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;

65

I i;i.foo(2);i.bar(2);

}

Page 66: 6 Continuacion C++

CastingsCastingsConstructores explícitos

Declaración “explicit” en un constructor, deshabilita este procedimiento. Ejemplo:p j p

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

P f ió j l “ idPara una función como por ejemplo “void g (Complejo c)” la llamada “g(3);” es incorrectaLa asignación de valores a los argumentos de una función se hace mediante llamadas a

666666constructor o constructor copia.

Page 67: 6 Continuacion C++

#include <iostream>using std::cout;

Constructores Explícitosclass H{

int x;bli

Constructores ExplícitosEjemplo

public: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";

} ¿Es correcto?}H & operator = (int val) {

x = val;cout << "asignacion\n";

¿Es correcto?

g ;return * this;

}};

•No es correcto: error C2664: 'foo' : cannot convert parameter 1 from

void foo(H c) { cout << "foo\n"; }

void main() {

'int' to 'H‘• Equivalente a H c = 2;

6767

() {H p(2); foo (2);

}

Page 68: 6 Continuacion C++

Castings

Para la clase

CastingsConstructores explícitos

Para la clase

class B {class B {Complejo c;

public:B(int x) : c(x) { }

};

la llamada “B b(3)” es correctaLas asignaciones de variables en constructores no utilizan a el goperador asignación sino un constructor.

“Complejo c=Complejo(4);” correcto686868

Complejo c=Complejo(4); correcto

Page 69: 6 Continuacion C++

Castings

Complejo & c(4); Complejo & c=4;

CastingsConstructores explícitos

Complejo & c(4); Complejo & c=4;incorrectos (tanto con explicit o sin él)

“const Complejo & c(4);” “const Complejo & c=4;”const Complejo & c(4); , const Complejo & 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 Complejo & c=Complejo(4); , const Complejo & c(Complejo(4));correctos (caso explicit o no explicit)

“Complejo c; c=4;”Complejo c; c=4; , correcto si no explicit y hay constructor por defecto, incorrecto si explicit, ya que se llama a “Complejo::operator=(const Complejo &)”. Podría ser correcto si se ha definido “Complejo & operator = (double val)”

696969

p j p ( )

Java usa constructores “explicit”

Page 70: 6 Continuacion C++

Castings

P bl d d ti l til d C

CastingsTipos

Problemas de uso de castings al estilo de C:Difícil detección y errores imprecedibles en castings incorrectosLocalización no trivial de castings en código (paréntesis con un tipo)Incoherencias con la conservación 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

li i i d d d “ t” “ l til ”const_cast: eliminar propiedades de “const” y “volatile”.dynamic_cast: para usar en sistemas jerárquicos de herenciareinterpret_cast: para realizar castings entre tipos no

707070

_relacionados

Page 71: 6 Continuacion C++

Castingsgstatic_cast

static_cast <type-id> ( expression ) No es tan seguro como dynamic_cast, ya que no hace comprobaciones en tiempo de ejecución.Normalmente para convertir de enumerados a enteros, o de punto flotante

_

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 sólo funciona con punteros o referencias, y el chequeo en tiempo de ejecución supone una sobrecarga. Además el “down cast” sólotiempo de ejecución supone una sobrecarga. Además el down cast sólo funciona con tipos polimórficos.

// static cast Operator.cpp// static_cast_Operator.cpp// compile with: /LDclass B {};class D : public B {};

void f(B* pb, D* pd) {D* pd2 = static_cast<D*>(pb); // “downcast”not safe, pb may point to just BB* pb2 = static cast<B*>(pd); // “upcast”: always a safe conversion

7171

pb stat c_cast (pd); // upcast a ays a sa e co e s o}

Page 72: 6 Continuacion C++

Castings// static_cast_Operator_2.cpp

gstatic_cast vs dynamic_cast

// compile with: /LD /GRclass B{

public:public:virtual void Test(){}

};class D : public B {};

void f(B* pb) {D* pd1 = dynamic_cast<D*>(pb);D* pd2 = static cast<D*>(pb);

Si pb apunta a un objeto de tipo D o a 0, pd1 y pd2 tendrán el mismo valor

D pd2 = static_cast<D >(pb);}

valor.

Si pb apunta a un objeto de tipo B, dynamic_cast devuelve cero,mientras que t ti t devuelve un puntero de tipo D de manera

7272

mientras que static_cast devuelve un puntero de tipo D de maneraincorrecta.

Page 73: 6 Continuacion C++

Castingsdynamic_cast < type-id > ( expression )

gdynamic_cast

type-id debe ser una clase definida anteriormente o un puntero a void.Sólo funciona para tipos polimórficos.Si type id es un puntero a una clase base accesible directa o indirectamente el

// dynamic_cast_1.cpp// compile with: /c

Si type-id es un puntero a una clase base accesible directa o indirectamente, el resultado es un puntero al sub-objeto de tipo type-id.

// compile with: /cclass B { };class C : public B { };class D : public C { };

void main () {D* pd = new D;C* pc = dynamic cast<C*>(pd); // ok: C es una clase base directaC pc = dynamic_cast<C >(pd); // ok: C es una clase base directa

// pc apunta al subobjeto de tipo C de pdB* pb = dynamic_cast<B*>(pd); // ok: B es una clase base indirecta

// pb apunta al sub-objeto de tipo B subobject de pd

737373

}

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

Page 74: 6 Continuacion C++

Castingsgdynamic_cast

dynamic_cast < type-id > ( expression )

Si el tipo de expression es una clase base de type-id, se chequea en tiempo de ejecución para ver si expression apunta realmente a un objeto completo de tipo type id

// dynamic cast 3 cpp

un objeto completo de tipo type-id. Si es así, el resultado es un puntero a un objeto de tipo type-id:

// dynamic_cast_3.cpp// compile with: /c /GRclass B {virtual void f();};class D : public B {virtual void f();};

void main() {B* pb = new D; // okB* pb2 = new B;B pb2 new B;

D* pd = dynamic_cast<D*>(pb); // ok: pb apunta a un DD* pd2 = dynamic_cast<D*>(pb2); // pb2 apunta a un B no a un D, se devuelve 0

}747474

}

Se llama “downcast” y dynamic_cast necesita tipos polimórficos.

Page 75: 6 Continuacion C++

#include <iostream>using namespace std;

class CCTest { Castingsclass CCTest {public:

CCTest(int a=0) : number(a) {}void setNumber( int num ) { number = num; }void printNumber() const;

gconst_cast

void printNumber() const;private:

int number;};void CCTest::printNumber() const {void CCTest::printNumber() const {

cout << "\nBefore: " << number;const_cast< CCTest * >( this )->number--;cout << "\nAfter: " << number;

}Salida

}

int main() {CCTest X;X setNumber( 8 );

Before: 8After: 7

X.setNumber( 8 );X.printNumber();

const CCTest & Y = X;const cast< CCTest &>(Y) setNumber(6);const_cast< CCTest &>(Y).setNumber(6);

const CCTest * Z = &X;const_cast< CCTest *>(Z)->setNumber(6);const cast< CCTest &>(*Z) setNumber(6);

757575

const_cast< CCTest &>( Z).setNumber(6);const CCTest U;const_cast< CCTest *>(&U)->setNumber(7);

}75

Page 76: 6 Continuacion C++

Atributos y Métodos de ClaseAtributos y Métodos de Clase

Acceso:Acceso:Global:

“NombreClase::variableOMetodo …”

En constructores y métodos de objeto:“this->variableOMetodo …”“variableOMetodo …”“NombreClase::variableOMetodo …”

En métodos de clase (“static”):“variableOMetodo …”“NombreClase::variableOMetodo ”NombreClase::variableOMetodo …

Inicialización de los atributos de clase desde fuera de las767676

Inicialización de los atributos de clase desde fuera de las clases (incluso siendo privados o protected).

Page 77: 6 Continuacion C++

#include "stdafx.h"#include <iostream>using namespace std; Ejemploclass Maze{

int x, y;public:

Maze(int x int y) : x(x) y(y) {}

j psingleton

Maze(int x, int y) : x(x), y(y) {}};

class MazeFactory {public:public:

static MazeFactory* Instance();// existing interface goes hereMaze * createMaze(int x, int y) { return new Maze(x, y); };

protected:protected:MazeFactory() {};

private:static MazeFactory* _instance;

};};

MazeFactory* MazeFactory::_instance = 0;

MazeFactory* MazeFactory::Instance () {MazeFactory MazeFactory::Instance () {if (_instance == 0) _instance = new MazeFactory;return _instance;

}

77void main(){

Maze * m = MazeFactory::Instance()->createMaze(10,10);}

Page 78: 6 Continuacion C++

Clases y Funciones AmigasClases y Funciones Amigas

“friend Clase;” o “friend

// classes_as_friends1.cpp// compile with: /cclass B;;

funcionOMetodo [codigo]” enuna clase A supone:

class B;class A {public:

int Func1( B& b );

Acceso posible a parte“private:” de la clase A desde la

private:int Func2( B& b );

};clase, función o método(NombreClase::nombreMetodo)amigos

};

class B {private:g

int _b;

// A::Func1 is a friend function to class B// so A::Func1 has access to all members of B// so A::Func1 has access to all members of Bfriend int A::Func1( B& );

};

( & ) { } // O787878

int A::Func1( B& b ) { return b._b; } // OKint A::Func2( B& b ) { return b._b; } // C2248

Page 79: 6 Continuacion C++

Funciones Amigas#include <iostream>

using std::ostream; Funciones Amigasusing std::ostream;using std::cout;

class Rect {static int max data;static int max_data;double x, y;int * data;

public:Rect(double cx = 0 double cy = 0) : x(cx) y(cy) data(new int[max data]) {Rect(double cx = 0, double cy = 0) : x(cx), y(cy), data(new 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);friend ostream & operator << (ostream& os, const Rect & r);

};int Rect::max_data = 10;

ostream & operator << (ostream& os const Rect & r) {ostream & operator << (ostream& os, const Rect & r) {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";return os << r.data[Rect::max_data-1] << ]}\n ;

}

void main() {

797979

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

}

Page 80: 6 Continuacion C++

Clases Amigas// classes_as_friends2.cpp// compile with: /EHsc#include <iostream>

Clases Amigas#include <iostream>

using namespace std;class YourClass {friend class YourOtherClass; // Declare a friend classfriend class YourOtherClass; // Declare a friend classpublic:

YourClass() : topSecret(0){}void printMember() { cout << topSecret << endl; }

private:private:int topSecret;

};

class YourOtherClass {class YourOtherClass {public:

void change( YourClass& yc, int x ){yc.topSecret = x;}};

int main() {YourClass yc1;YourOtherClass yoc1;yc1 printMember();

8080

yc1.printMember();yoc1.change( yc1, 5 );yc1.printMember();

}

Page 81: 6 Continuacion C++

Clases y Funciones Amigas

L i d í

Clases y Funciones Amigas

La amistad no es recíproca a no ser que se especifique explícitamente:

class Base{

fclass B {

friend class A;...

friend class aFriend;};

class Derived : public Base};

class A {friend class B;

class Derived : public Base{};

l F i d amiga defriend class B;...

};

class aFriend{

friend class anotherFriend;};

amiga_de

La amistad no se hereda (una subclase de A no puede acceder a miembros privados

};

class anotherFriend{}

amiga_de

8181

acceder a miembros privados de B), ni es transitiva.

};

Page 82: 6 Continuacion C++

#include "stdafx.h"class Base{ Clases Amigasfriend class aFriend;private:

int x;public:

Base(int n = 0 ) : x(n) {}

Clases AmigasEjemplo

( ) ( ) {}};

class Derived : public Base{private:private:

int y;public:

Derived (int k = 3) : Base(k), y(k) {}};

class aFriend{

friend class anotherFriend;public:p

aFriend( Derived & d) {d.x = 9;d.y = 7; // error C2248

}};};

class anotherFriend{public:

th F i d( B & b ) { b 0 } // // C2248

828282

anotherFriend( Base & b ) { b.x=0; } // // error C2248};

void main() { }

Page 83: 6 Continuacion C++

IndiceIndiceTipos y Declaraciones.p yFunciones.ClasesClases.Espacios de Nombres.p

AmbitoBiblioteca Estándar (STL)Biblioteca Estándar (STL).Herencia.Manejo de Errores.Entrada/Salida.

838383

Entrada/Salida.83

Page 84: 6 Continuacion C++

Ambito de variablesAmbito de variables.

Las variables se pueden definir en distintos ámbitosLas variables se pueden definir en distintos ámbitos anidados.

La referencia a una variable se refiere al ámbito más cercano:

int x=7;void main(int argc, char* argv[]) {{

int x=8;{

int x=9;;cout << “Valor:” << x; // Valor:9

}}

848484Uso del operador de ámbito ‘::’

Page 85: 6 Continuacion C++

Espacios de Nombres (namespace)Espacios de Nombres (namespace)

L i d bLos espacios de nombres son un mecanismo para modularizar los programas.

Útiles sobre todo para programas grandes.

Permite agrupar elementos (clases, e te ag upa e e e tos (c ases,funciones, variables, tipos, etc.) lógicamente relacionados.

Un espacio de nombres define un ámbito.858585

Un espacio de nombres define un ámbito.

Page 86: 6 Continuacion C++

Espacios de NombresPosible anidamiento: el espacio de nombres puede ser:

Espacios de NombresPosible anidamiento: el espacio de nombres puede ser:

espacioNombres1::espacioNombres2::espacioNombres3:: …

Por defecto está definido el espacio de nombres vacío (se incluyenPor defecto está definido el espacio de nombres vacío (se incluyen la función “main”, y las variables, funciones y clases no asignados a ningún espacio de nombres)

Las clases definen también un ámbito (nombre de la clase). Los elementos de ese espacio de nombres son variables, métodos, clases, …,

Se pueden definir espacios de nombres anónimos.

Llamadas posibles a elementos de un espacio de nombres mediante:

espacioNombres::elemento

868686

espacioNombres::elemento

Page 87: 6 Continuacion C++

Espacios de Nombres

int b=11;

Espacios de NombresEjemplo

int b=11;int b=11;namespace NS1 {

int a=1; int b=2;

namespace NS1 {

int a=1; int b=2;

NS2 // NS2 id dint b=2;namespace NS2 // NS2 anidado{

int a=3; int b=4;

namespace NS2 // NS2 anidado{

int a=3; int b=4;

id f()int b=4; void f() {} class A {};

}}

void f(); class A {};

}}

}

int x=7;

void main()

void NS1::NS2::f() { std::cout << "f\n"; }

int x=7;void main() {

NS1::a=7;NS1::NS2::f();::x=34;

void main() {

NS1::a=7;NS1 NS2 f()

878787

::x=34;}

NS1::NS2::f();::x=34;

}

Page 88: 6 Continuacion C++

Espacios de Nombres

U dif t fi h

Espacios de Nombres

Uso en diferentes 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 funciónint h = 4; // extender lo que hay en NS

}... main (...) {

NS::x=7;NS f()

888888

NS::f();. . .

Page 89: 6 Continuacion C++

Espacios de Nombres

Sirven para ocultar nombres a otros ficheros

Espacios de NombresEspacios anónimos

Sirven para ocultar nombres a otros ficheros.

Protección contra “colisiones de nombres”.

Los espacios de nombres anónimos en distintos ficheros son distintos.

No hay manera de acceder a un nombre de un espacio de nombres anónimo de un fichero distinto.

#include “header.h”namespace {

i t

#include “header.h”namespace $$$ {

int a;int a;void f() {/* … */}void g() {/* … */}

}

int a;void f() {/* … */}void g() {/* … */}

}i $$$ // $$$ b ú i

equivale a

898989

} using namespace $$$; // $$$ es un nombre único

Page 90: 6 Continuacion C++

Espacios de Nombres

Permite llamar a elementos de un espacio de nombres

Espacios de Nombresusing namespace

Permite llamar a elementos de un espacio de nombres directamente sin poner explícitamente el espacio de nombres donde se encuentra

Instrucción ejecutable en cualquier ámbito (donde fuera aceptable por ejemplo la instrucción “int u=7;”)aceptable, por ejemplo, la instrucción int u 7; )

Sintaxis: “using namespace espacioDeNombres”;

Esta declaración se aplica por defecto para cualquier ámbito para el espacio de nombres vacío y para losámbito para el espacio de nombres vacío y para los espacios de nombres anónimos

909090

Page 91: 6 Continuacion C++

Espacios de Nombres

i t 10

void main(int argc, char* argv[]) {using namespace NS2;using namespace std;

Espacios de NombresEjemplo

int a=10;namespace NS1{

int a=1;

using namespace std;int a=8; cout << "Valor:" << d; // Valor 7f();int a=1;

int c=4;void f(){};

}

f(); {

using namespace NS1;cout << "Valor:" << a; // Valor 8}

namespace NS2 {

int d=7;

cout << Valor: << a; // Valor 8// Al comentar la línea // "int a=8;" se produce // un error de ambigüedad int d 7;

void f(){};}namespace

// gcout << "Valor:" << b; // Valor 3cout << "Valor:" << c; // Valor 4cout << "Valor:" << ::a; // Valor 10p

{int b=3;

}

// f(); incorrecto por ambigüedad}

}

919191

Page 92: 6 Continuacion C++

Espacios de Nombres

Sintaxis:

Espacios de NombresUso de elementos

Sintaxis:using espacioDeNombres::elemento;

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

Si el elemento declarado es una variable, no se puede definir en ese ámbito otra variable con el mismo nombreá b to ot a a ab e co e s o o b eSi el elemento declarado es una función (f), no se puede hacer una llamada a otra declaración “using otroEspacioNombres::f;” en el mismo ámbito

AlgoritmoEn un ámbito determinado, al hacer una llamada a una variable, función o clase se mira en ámbitos anidados las posibles definicioneso clase, se mira en ámbitos anidados las posibles definiciones (incluyendo las declaraciones individuales de “using”) hasta el ámbito más global. En el ámbito global se incluyen los elementos declarados mediante las declaraciones conjuntas de “using” que afectan a la llamada a la variable función o clase

929292

llamada a la variable, función o clase.

Page 93: 6 Continuacion C++

Espacios de Nombres

int a=10;

void main(int argc, char* argv[]) {using std::cout;using NS1::a;

Espacios de NombresEjemplo

int a=10;namespace NS1 {

int a=1;

using NS1::a;// int a=8; es incorrectousing NS2::d;using NS1::f;int a 1;

int c=4;void f(){};

}

// using NS2::f; incorrecto por ambigüedad{

using NS2::f;}namespace NS2 {

int d=7;

f(); // ejecucion de NS2::f()// si hubieramos hecho la declaracion // “using namespace NS2;”en lugar de la// declaracion “using NS2::f”; la ejecucion

void f(){};}namespace

// declaracion using NS2::f ;, la ejecucion // habria sido de NS1::f();

int d=37;cout << "Valor:" << a; // Valor 1

{int b=3;

}

cout << "Valor:" << d; // Valor 37cout << "Valor:" << NS2::d; // Valor 7

}

939393

}

Page 94: 6 Continuacion C++

Búsqueda de espacios de nombres

Es probable que una función que usa un tipo T se haya definido en el mismo espacio de nombres.Si f ió t l á bit dSi una función no se encuentra en el ámbito de su uso, se busca en el ámbito de sus argumentos.

namespace A{

class B {};class B {};void f (B & b) {};

};

id i ()void main(){

A::B b;f ( b );

949494

f ( b );}

Page 95: 6 Continuacion C++

IndiceIndiceTipos y Declaraciones.F iFunciones.Clases.Espacios de Nombres.p

La Biblioteca Estándar (STL).Introducción.Plantillas.Contenedores.Iteradores.Algoritmos y Objetos Función.Adaptadores.

Herencia.Manejo de Errores

959595

Manejo de Errores.Entrada/Salida. 95

Page 96: 6 Continuacion C++

La Biblioteca EstándarLa Biblioteca EstándarDesarrollada por Stepanov A y Lee M de HPDesarrollada por Stepanov, A. y Lee M de HP.Programación genérica, uso extensivo de plantillas.Incluye:

L bibli t tá d d CLa biblioteca estándar de CLos contenedores (son templates)

<vector>, tabla unidimensional, <list>, lista doblemente enlazada, < t> j t < > di i i < t i > d l til d<set>, conjunto, <map>, diccionario, <string> cadena al estilo de C++

Entrada/Salida: <iostream> que contiene cin cout y cerr<iostream>, que contiene cin, cout y 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 y , p ), , jarchivos

Otros: <algorithm>, que contiene algoritmos generales como ordenación,

969696

Page 97: 6 Continuacion C++

La Biblioteca Estándar

P t i t l i d b “ td”

La Biblioteca Estándar

Perteneciente al espacio de nombres “std”

La parte de la biblioteca estándar de C++ que contiene templates (clases o funciones), se ll “Bibl t E tá d d Pl till d C ”llama “Bibloteca Estándar de Plantillas de C++” (STL, Standard Template Library)

< ector> <string> <algorithm><vector>, <string>, <algorithm>, …

Alguna referencia STL:Alguna referencia STL:http://www.sgi.com/tech/stl/

979797

Page 98: 6 Continuacion C++

La Biblioteca Estándar de C

L bibli t tá d d C tá d fi id

La Biblioteca Estándar de C

Las bibliotecas estándares de C están definidas en la biblioteca estándar de C++ en el espacio de nombres “std” y en los ficheros cabecera:de nombres std y en los ficheros cabecera:

<cstdio>, <cmath>, …Por ejemplo <cmath> es:Por ejemplo, <cmath> es:

namespace std {#include <cmath.h>

}

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

989898

Page 99: 6 Continuacion C++

Plantillas de ClasePlantillas de ClasePlantillas de métodos y de clases:Plantillas de métodos y de clases:

Uso de “class” o “typename” como parámetrosSe compilan sus instanciaciones

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

Incorrecto “ class Clase<T1 T2 > { };”Incorrecto … class Clase<T1,T2, …> {…};

Las plantillas de clases pueden tener:Argumentos que sean tipos, constantes de tipos primitivos g q p p p(no valen punto flotante ni strings) o punteros. Ejemplo:

template <int x, int y, class T> class Matriz {…};Argumentos opcionales con valores por defecto (sólo lasArgumentos opcionales con valores por defecto (sólo las plantillas de clase). Ejemplos:

template <int x, int y=1, class T=int> class Matriz {…};• Matriz<3> m;

999999

Matriz 3 m;template <class T1, T2=vector<T1> >

class UnaPlantilla {…};

Page 100: 6 Continuacion C++

Ejemplo

template <int x, int y, class T> class Matriz {

T ** val;int dx, dy;

bli Ejemplopublic:Matriz () : dx(x), dy(y) {

val = new T [dy][dx];std::cout << "Def1";for (int i = 0; i < dy; i ++)for (int i = 0; i < dy; i ++)

for (int j=0; j < dx; j ++ )val[i][j] = 0;

} // válido también Matriz<x,y,T>() Matriz (int x);( );void f();~Matriz() {

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

Encuentra el Error}

};

template <int x, int y, class T> Matriz<x,y,T>::Matriz(int x) : dx(x), dy(y) { // el parámetro x del constructor oculta el parámetro del template{ // el parámetro x del constructor oculta el parámetro del template

val = new T * [dy]; // val = new T [dy][dx]; no vale xq dx no es constantefor (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 ++ )for (int j 0; j dx; j )val[i][j] = 0;

std::cout << "Def1";}// incorrecto: Matriz::Matriz(int x) {};

100100

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 parámetros del template

Page 101: 6 Continuacion C++

template <int x, int y, class T> class Matriz {

T * val[y];int dx dy; Ejemploint dx, dy;

public:Matriz () : dx(x), dy(y) {

for (int i = 0; i < dy; i ++) val[i] = new T [x];std::cout << "Def1";

Ejemplostd::cout << Def1 ;for (int i = 0; i < dy; i ++)

for (int j=0; j < dx; j ++ )val[i][j] = 0;

} // válido también Matriz<x y T>()} // válido también Matriz<x,y,T>() Matriz (int x);void f();~Matriz() {

for (int i = 0; i < dy; i ++) delete [] val[i];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)template <int x, int y, class T> Matriz<x,y,T>::Matriz(int x) : dx(x), dy(y) {

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 ++ )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; }

Page 102: 6 Continuacion C++

Ejemplo

template <> class Matriz<2 3 int> {

EjemploEspecialización de Plantillas de clases

template <> class 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*> {public: Matriz<2,3,T*> () {cout << “Def4";}p , , () { ;}};

/* C++ determina (mediante “pattern matching”) que:- Def2 es especialización de Def3, Def1- Def3 es especialización de Def1- Def4 es especialización de Def1

102102102

*/

Page 103: 6 Continuacion C++

EjemploEjemploEspecialización de Plantillas de clases

id i ()void main(){

Matriz<3,4,int> m1;// Def:1 Definiciones posibles: 1Matriz<2,3,int> m2;// Def:2 Definiciones posibles: 1 2 3// Def:2 Definiciones posibles: 1,2,3.// Se elige, si existe, aquella que es// especialización de todas las demásMatriz<2,3,char> m3;// Def:3 Definiciones posibles: 1,3Matriz<2 3 char*> m4;Matriz<2,3,char > m4;// Def:4 Definiciones posibles: 1,4

}

103103103

Page 104: 6 Continuacion C++

EjemploEjemploEspecialización 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";// excepción: sólo en una instanciación 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 función, incluyendo argsvoid main(){

double d=3;int j = 7;

intercambia(j, d); //Def1, def posibles: 1,2

104104104

intercambia(j, j); //Def2intercambia(vector<int>(), vector<int>()); //Def3, def posibles: 1, 3intercambia(vector<char>(), vector<int>());//Def1

}

Page 105: 6 Continuacion C++

Ejemplo

Ob ió i d á t l f ió

EjemploEspecialización de Plantillas de funciones

Observación: si además tenemos la función:

void intercambia (int & t1, int & t2) {std::cout << "Def4";

}

void main(){int x=3 y=5;int x=3,y=5;intercambia(x,y); // Def:4 Defs posibles: 1,2,4

}

105105105

Page 106: 6 Continuacion C++

TemplatesTemplatesUn argumento de un template puede a su vez ser unUn argumento de un template puede a su vez ser un template:

#include <iostream> #include <iostream>#include <iostream>

template <class T> class c1 {public:

#include iostream

template <class T> class c1 {public:

T tT t;};

template <template<class A> class T>

T t;};

template <template<class A> class T, class R>template <template<class A> class T> class c2 {public:

T<int> atrib;

template template class A class T, class R class c2 {public:

T<R> atrib;}};

int main() {c2<c1> myc2;

};

int main() {c2<c1, int> myc2;

106106

c2<c1> myc2;myc2.atrib.t = 5;std::cout << myc2.atrib.t;

}

c2 c1, int myc2;myc2.atrib.t = 5;std::cout << myc2.atrib.t;

}

Page 107: 6 Continuacion C++

TemplatesTemplates

Typenameclass Z{public:

class U{};};

template <class B>class A{

typename B::U x;}};

void main(){

107

{A<Z> a;

}

Page 108: 6 Continuacion C++

Plantillas de métodosPlantillas de métodos

Similares a plantillas de funciones globales.

class X {class X {public:

template <class T> void f ();template <class T> void g (){};p g (){}

};

template <class T> void X::f() {//”X::f<T>” incorrecto// X::f<T> incorrecto

}

void main () (){

X x;x.f<int>();

// “x f();” incorrecto porque no asigna valor a T

108108108

// x.f(); incorrecto porque no asigna valor a T}

Page 109: 6 Continuacion C++

Plantillas de métodosPlantillas de métodostemplate <int x int y class T>template <int x, int y, class T> 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>template <int x, int y, class T> template <class H>void Matriz<x,y,T>::f() {}

109109109

Page 110: 6 Continuacion C++

ContenedoresContenedores

Clases que almacenan objetos de algún (otro) tipo.Secuenciales: almacenan la colección de objetos del mismo tipo de manera lineal.

vector, list, deque.Asociativos: proporcionan la capacidad deAsociativos: proporcionan la capacidad de recuperación rápida de información basada en claves.claves.

Clave única: set, map. Múltiples objetos con igual clave: multiset multimap

110110

Múltiples objetos con igual clave: multiset, multimap.110

Page 111: 6 Continuacion C++

VectorVectorConjunto de elementos en un orden lineal

Acceso secuencial: uso de una clase “iterator”Acceso secuencial: uso de una clase iteratorAcceso aleatorio a elementos (uso de “[ ]”)

Permite inserción y borrado. Eficiencia:Al final: O(1), En el medio: O(n)

Principales operaciones: C t t t t () t t (i t) t ( t t &)Constructores: vector::vector(), vector::vector(int), vector(const vector &)vector::size(), vector::resize(int)Acceso (lectura/escritura) a primer, último y cualesquiera elementos:

T& vector<T>::front() constT& vector<T>::front() const T& vector<T>::back() constT& vector<T>::operator[](vector::size_int) const

• En “T& vector<T>::at (vector::size) const” se lanzan excepciones en ( )accesos erróneos; menos eficiente que “[]”

vector& vector::operator=(const vector&). Asignación elemento a elemento

111111111bool operator==(const vector&, const vector&). Comparación de elementos

Page 112: 6 Continuacion C++

ContenedoresOperaciones y Eficiencia

112112112

Page 113: 6 Continuacion C++

VectorEj l (1)

#include<vector>

#include<iostream> Ejemplo (1)#include<iostream>

using namespace std;

int main() {

ecto <int> intV(10) // ecto int de 10 elementosvector<int> intV(10); // vector int de 10 elementos

for(int i = 0; i < intV.size(); intV[i] = i++); // acceso aleatorio

// el vector se agranda

i i i 100 // i 100intV.insert(intV.end(), 100); // añadir el numero 100

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 = ";

113113113for(int i = 0; i < intV.size(); cout << intV[i++] << " ");

}

Page 114: 6 Continuacion C++

Vectorvector<long> grupo(10); // 10 elementos

VectorEjemplo (2)

// se inicializan con el const. X defecto.vector<short> u; // vector vacíovector<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 5cesta.resize(3); // el vector pasa a tener 3 elementosvector<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)"

114114114

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}

Page 115: 6 Continuacion C++

Vector

GUI t ió lé t i

Ejemplo

GUI para una estación eléctrica:

Shape GUI_PEgui_shapes#include <iostream>#include <vector>

Turbine Pipe Switch Horn

using std::vector;

class Shape { /*…*/};Turbine Pipe Switch Horn

Electrical Mecanical

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

//…Electrical

SwitchMecanical

Switch class GUI_PE{vector <shape> gui_shapes;

public:public:GUI_PE() : gui_shapes() {}GUI_PE & addShape( Shape & s) {gui shapes push back(s);

115115115

gui_shapes.push_back(s); }

};

Page 116: 6 Continuacion C++

Vector#include <iostream>#include <vector>

VectorInserción/Reemplazo de elementos.

#include <vector>

using namespace std;

void main(){

vector<short> u; // vector vacíou 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;std::cerr << Tipo: << typeid( r ).name( ) << endl;

}u[2] = 3; // error en tiempo de ejecución

}

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

Page 117: 6 Continuacion C++

Vector

assign : Borra un vector y copia los elementos especificados al vector vacío

VectorMiembros

assign : Borra un vector y copia los elementos especificados al vector vacío.at: Devuelve una referencia al elemento en la posición 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 podría contener sin reservar más memoria.clear: Borra los elementos del vector.empty: Comprueba si el vector está vacio.end: Devuelve un iterador de acceso aleatorio al último elemento más 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 posicióninsert: Inserta un elemento o grupo de elementos en el vector en una cierta posición.max_size: Devuelve la longitud máxima del vector. pop_back: Borra el elemento final del vector.push_back: Añade 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 tamaño para el vector.reserve: Reserva una longitud mínima de almacenamiento para el vector.

117117

reserve: Reserva una longitud mínima de almacenamiento para el vector.size: Devuelve el número de elementos del vector.swap: Intercambia los elementos de dos vectores.operator[]: Devuleve una referenca al elemento del vector en cierta posición.

Page 118: 6 Continuacion C++

La interfaz de los contenedoresLa interfaz de los contenedores

Tipo de Datos SignificadoX::value type T_ ypX::reference Tipo de la referencia a los elementos del

contenedorX const reference Idem para solo lect raX::const_reference Idem para solo lectura

X::iterator Tipo del iteradorX t it t Ti d l it d t tX::const_iterator Tipo del iterador constante

X::difference_type Tipo entero con signo para distancia entre elementos (diferencia entre dos punteros)elementos (diferencia entre dos punteros)

X::size_type Tipo entero sin signo para especificaciones de tamaño.

Page 119: 6 Continuacion C++

La interfaz de los contenedoresMétodos. Contenedores.

Método SignificadoMétodo SignificadoX() Constructor por defecto, crea un contenedor vacío.

X(const X&) Constructor copia.

~X() Destructor, llama al destructor de cada elemento del contenedor

iterator begin() Principio del contenedor

const_iterator begin() Principio del contenedor

iterator end() Posición después del último elemento

const_iterator end() idem

size_type max_size() Tamáño máximo posible del contenedor

size_type size() Tamaño actual del contenedor

bool empty() size() == 0, o bien begin() == end()

void swap(X&) Intercambia elementos con el contenedor argumento.void swap(X&) Intercambia elementos con el contenedor argumento.

X& operator=(const X&) bool operator==(const X&) bool operator!=(const X&) bool operator<(const X&) booloperator<(const X&) bool operator>(const X&) bool operator<=(const X&) bool operator>=(const X&)

Page 120: 6 Continuacion C++

La interfaz de los contenedores

Se pueden recorrer de atrás hacia delante.Contenedores Reversibles.

pX::reverse_iteratorX::const_reverse_iteratorb i () // i t t l t l trbegin() // points to last element

rend() // points to fictitious position before the first element

t < t i > t i V (4)vector<string> stringVec(4);stringVec[0] = "First"; stringVec[1] = "Second"; stringVec[2] = "Third"; stringVec[3] = "Fourth";stringVec.insert(stringVec.end(), string("Last")); //incremento de tamañocout << "size() = " << stringVec.size() << endl; // 5vector<string>::iterator I = stringVec.begin();++I; // 2nd positionstringVec erase(I); // delete SecondstringVec.erase(I); // delete Secondcout << "size() = " << stringVec.size() << endl; // 4for(I = stringVec.begin(); I != stringVec.end(); ++I) cout << *I << endl;for(vector<string>::reverse_iterator revI = stringVec.rbegin();

revI != stringVec.rend(); ++revI)cout << *revI << endl;

Page 121: 6 Continuacion C++

Clase stringClase string

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

Operadores ”[]”, “at”, “==“ similares a “vector”“string::append” añade un string al final“string::append” añade un string al finalOperadores “+” y “+=“ (concatenación de cadenas)Operador “<<“ (salida de datos)Conversión a “char*”: “string::c_str()”

El destructor de “string” elimina la cadena de caracteres

121121121

Page 122: 6 Continuacion C++

Clase string

#include <iostream>

Clase stringEjemplo

#include <iostream>#include <string>

using std::string;using std::string;using std::cout;

void main(int argc, char* argv[]) {( g , g []) {string cad1; // cadena vacíastring 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:012str1.append(str2);

// "string & std::string::append(string&)"//

122122122

cout << "Valor:" << str1; // Valor:012345// "ostream & operator<<(ostream &, string &)"

}

Page 123: 6 Continuacion C++

Clase string

const char * q;

Clase stringEjemplo

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

123123123

Page 124: 6 Continuacion C++

MapMap

Conjunto de pares clave-valor. Dos pares no pueden tener la misma clave (mediante p (operador “==“).

Es conjunto ordenado (se puede recorrer el j t d di t it d ) úconjunto de pares mediante un iterador) según

los valores de “clave”

124124124

Page 125: 6 Continuacion C++

Map

map<string string> agenda;

MapEjemplo

map<string, string> agenda;agenda["Elena"] = "91-2837363";agenda["Fernando"] = "965-243396";agenda["Ruth"] = "95-2363204";agenda[ Ruth ] = 95 2363204 ;agenda["Carlos"] = "91-4807303";cout << agenda["Ruth"] << endl;agenda.erase (agenda.find ("Fernando"));agenda.erase (agenda.find ( 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 alfabético)// pair<T1, T2> está definida en <utility>

125125125

Page 126: 6 Continuacion C++

MapMapEjemplo

map<string, string,greater<string>> agenda;agenda["Elena"] = "91-2837363";

d ["F d "] "965 243396"agenda["Fernando"] = "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++) {

t << "[" << >fi t << " "cout << "[" << z->first << "," << 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

}

Page 127: 6 Continuacion C++

#include <iostream>#include <map> Map#include <map>#include <string>

using namespace std;

MapEjemplo

typedef map<string, int> Tabla;

void readitems (Tabla & m){{

string word;int val = 0;while (cin >> word >> val) m[word] += val;

} ConsolaPCs 12 discos 10 PCs 12 fin finPCs 24discos 10

}

void main(){

Tabla tbl;

Consola

discos 10------------------------------total 34

Tabla tbl;readitems (tbl);

int total = 0;typedef Tabla::const iterator CI;typedef Tabla::const_iterator CI;for (CI p=tbl.begin(); p!=tbl.end(); ++p){

total += p->second;cout << p->first << '\t' << p->second << '\n';

127

cout << p->first << \t << p->second << \n ;}cout << "------------------------------\ntotal\t" << total << '\n';

}

Page 128: 6 Continuacion C++

#include<map>#include<string>#include<iostream>using namespace std; Mapusing namespace std;// two typedefs for abbreviations// comparison object: less<long>()typedef std::map<long, std::string> MapType;

i

MapEjemplo

typedef MapType::value_type ValuePair;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;std::cin >> Number;if((iter = Map.find(Number))!= Map.end()) std::cout << (*iter).second;else std:: cout << "Not found!";

}

Page 129: 6 Continuacion C++

Otros Contenedores STLOtros Contenedores STL

tsetConjunto ordenado (según “<“) de elementos sin repeticionesrepeticiones.

multiset.Conjunto con repeticiónConjunto con repetición.

hash_setUn diccionario ordenado con uso de “hashing”Un diccionario ordenado con uso de hashing

listUna lista doblemente enlazadaUna lista doblemente enlazada

. . .

129129129

Page 130: 6 Continuacion C++

IteradoresIteradores

G li ió d l d iGeneralización de puntero a un elemento de una secuencia:Dereferencia (* y ->).Apuntar al próximo elemento (++).Apuntar al próximo elemento ( ).Comparación (==, !=).

Toda plantilla de función que toma un iterador como parámetro 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.

130130

Page 131: 6 Continuacion C++

IteradoresIteradoresbegin() end()

elem[0] elem[1] elem[2] elem[n-1]

begin() end()

elem[0] elem[1] elem[2] elem[n 1]…

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

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

131131

vector: iterador de acceso aleatorio.list: bidireccional.

Page 132: 6 Continuacion C++

Iteradores

#include <iostream>

IteradoresEjemplo input y output iterator

#include <iostream>#include <algorithm>#include <fstream>#include <string> esto es una frase

words.txtesto salida

using namespace std;

int main( ) { ifstream ifile("words txt");

es una frase

ifstream 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"));// también equivalente a: // string s;// ( f ) \

132132

// while (ifile >> s) cout << s << "\n";ifile.close();

}

Page 133: 6 Continuacion C++

Ejemplo#include <iostream>#include <iterator>#include <vector> Ejemplo

Iteradores como parámetros#include <list>

using namespace std;

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 << " ";

struct std::random_access_iterator_tag

cout << x << " ";i1++;

}; cout << endl;

salida

a a a a a a a a a astruct std::bidirectional_iterator_tag0 0 0 0 0 0 0 0 0 0struct std::random access iterator tag

;};

int main( ) {vector<char> vc( 10 'a' ); struct std::random_access_iterator_tag

1 2 3 4 5 6 7 8 9vector<char> vc( 10,'a' );list<int> li( 10 );double v[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};function( vc.begin( ), vc.end( ) );

133133

( g ( ) ( ) )function( li.begin( ), li.end( ) );function( v, v+10);

}

Page 134: 6 Continuacion C++

EjercicioEjercicioDel examen de Febrero 2008

(20 puntos): El método “main” siguiente (cuyo resultado se(20 puntos): El método main siguiente (cuyo resultado se muestra más abajo) utiliza un iterador secuencial (posiciones 1, 2, 3, etc) de un vector. Completar el programa para que sea válido en un caso general (no sólo “int” y no sólo los valores {4,5,6} en g ( y { , , }las posiciones {1,2,3}): void main() {

vector<int> v;vector<int> v;v.push_back(4);v.push_back(5);v.push_back(5);Iterador<int> q1(&v);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 6Iterador:posicion=3,vector= 8 8 8Iterador:posicion=4,vector= 8 8 8

Page 135: 6 Continuacion C++

Ejercicioje c c oSolución

template <class T>class Iterador {private:vector<T> * v;int posicion;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;cout << endl;}

};

Page 136: 6 Continuacion C++

EjercicioEjercicioModificar la clase Iterador<X> para que

void main ()

p qtambién 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();f ( ! fi li d () ) * 'd'for (; !y.finalizado(); ++y) *y='d'; y.imprime();

}

Page 137: 6 Continuacion C++

SoluciónSolución

template<class Elemento>class Iterador {vector<Elemento> v;int posicion;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;}Iterador<Elemento> operator ++() {p () {

posicion++;return *this;

}Elemento & operator * () { return v[posicion];}Elemento & operator * () { return v[posicion];}void imprime () {

cout << "Iterador:posicion=" << posicion << ",vector=";for (int i=0; i < max; cout << "\t" << v[i++] );cout << endl;

}};

Page 138: 6 Continuacion C++

Algoritmos de la STLAlgoritmos de la STL

C tCuatro grupos:Operaciones secuenciales constantes (no cambian el orden de la secuencia).)

for_each, find, find_if, adjacent_find, …Operaciones secuenciales cambiadoras (pueden cambiar el orden de la secuencia)cambiar el orden de la secuencia).

transform, copy, swap, replace, fill, reverse, …Operaciones de ordenación y relacionadas.

sort, lower_bound, upper_bound, merge, …Operaciones numéricas generalizadas.

accumulate, count, count if, …accumulate, count, count_if, …

Es necesaria la cabecera <algorithm>138138

g

Page 139: 6 Continuacion C++

Algoritmos de la STL#include <iostream>#include <vector>

Algoritmos de la STLEjemplo for_each

#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 back(1);u e os.pus _bac ( );numeros.push_back(2);

sort(numeros.begin(), numeros.end());for each(numeros.begin(), numeros.end(), f);_ ( g (), (), );for_each(nums, nums+3, f);

// EJECUCIONES EQUIVALENTESsort<vector<int>::iterator> (numeros.begin(), numeros.end());

139139139

( g (), ());for_each<vector<int>::iterator> (numeros.begin(), numeros.end(), f); for_each<int*>(nums, nums+3, f);

}

Page 140: 6 Continuacion C++

Algoritmos de la STL#include <iostream>#include <vector>#include <algorithm> Algoritmos de la STL

Ejemplos (plantilla)using namespace std;

template<class In, class Op> Op & ff e(In first In last Op & f) { // similar a for eachOp & ff_e(In first, In last, Op & f) { // similar a for_each

while (first != last) f(*first++);return f;

};

class objFun{

int acum;public: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() {void main() {vector<int> v(6, 7);objFun ob;ff_e(v.begin(), v.end(), ob);ob print();

140140140

ob.print();int b [6] = {1, 2, 3, 4, 5, 6};ff_e(b, b+5, f);

}

Page 141: 6 Continuacion C++

Algoritmos y #include "stdafx.h"#include <iostream>#include <algorithm># Objetos Función#include <deque>using std::ostream;

template <class T>lclass sum_up

{public:

void operator() (const T & value ) { sum += value; }f i d t & t ( t & T )friend ostream & operator << (ostream & os, sum_up<T> s);

private:static T sum;

};

int sum_up<int>::sum = 0;

inline ostream & operator << (ostream & os, sum_up<int> s) {treturn os << s.sum;

}

void main() {i td d

6salida

using std::deque;using std::cout;

deque<int> d(3, 2);i t

141141

sum_up<int> s;for_each (d.begin(), d.end(), s);cout << s;

}

Page 142: 6 Continuacion C++

Ejemplo find if#include <iostream>#include <algorithm> Ejemplo find_if#include <vector>

using std::ostream;

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:private:T x;

};

void main(){

using std::vector;using std::cout; 4

salidausing std::cout;

vector<int> v(5);for (int i=0; i < 5; v[i++]=i); //v[] = {1, 2, 3, 4, 5}

i i i fi d if ( b i () d() fi d fi i (3))142142

vector<int>::iterator it = find_if (v.begin(), v.end(), find_first_greater<int>(3));it != v.end() ? cout << *it : cout << "not found";

}

Page 143: 6 Continuacion C++

Ejemplo sortEjemplo sort

#include <iostream>#include <algorithm>#include <vector>

inline bool greater ( int a, int b ) { return a > b; }

void main(){

using std::vector;i td t salidausing std::cout;

vector<int> v(5);for (int i 0; i < 5; v[i++] i); // v[] {1 2 3 4 5}

54321salida

for (int i=0; i < 5; v[i++]=i); // v[] = {1, 2, 3, 4, 5}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++);

143143

for (VCI first = v.begin(); first != v.end(); cout << first++);}

Page 144: 6 Continuacion C++

Ejemplo sortEjemplo sort

#include <iostream>#include <algorithm>#include <functional>#include <functional>#include <vector>

using namespace std;using namespace std;

void main(){ salida{

vector<int> v(5);for (int i=0; i < 5; v[i++]=i); // v[] = {1, 2, 3, 4, 5}

54321salida

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++);

144

( g () () )}

Page 145: 6 Continuacion C++

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

int main () {vector <float> rgFA(10); ostream_iterator <float> OstreamIt(cout," "); 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

salida

// Initialize the array to 1,1/2,1/3,...for (int i=0; i<10; rgFA[i++]=(1.0f/i) );// Print the arraycopy(rgFA.begin(),rgFA.end(),OstreamIt);

The product of 1 * 1/2 * 1/3 * ... * 1/10 is 2.75573e-007The concatenated vector of strings: This is one sentence.

cout << endl;// Sum the arraycout << "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// Compute the product of the arraycout << "The product of 1 * 1/2 * 1/3 * ... * 1/10 is "<< accumulate(rgFA.begin(),rgFA.end(),1.0f,multiplies<float>())<< endl;

// Initialize array of stringsvector<string> rgs;g g ;rgs.push_back("This ");rgs.push_back("is ");rgs.push_back("one ");rgs.push_back("sentence. ");

145145// Concatenate the strings in the array and print the sentencecout << "The concatenated vector of strings: "<< accumulate(rgs.begin(),rgs.end(),string(""))<< endl;

}

Page 146: 6 Continuacion C++

Ejemplo count if#include <iostream>#include <algorithm>#i l d f ti l Ejemplo count_if#include <functional>#include <string>#include <vector>

She Sells Sea Shells by the Sea Shoresalida

using namespace std;

// Return true if string str starts with letter 'S'int MatchFirstChar( const string& str) {return str[0] == 'S';}

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

int MatchFirstChar( const string& str) {return str[0] S ;}

int main(){ vector<string> NamesVect(8) ; //vector containing names

NamesVect[0] = "She" ;NamesVect[1] = "Sells" ;NamesVect[2] = "Sea" ;N V t[3] "Sh ll "NamesVect[3] = "Shells" ;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 ;

146146

cout endl ;ptrdiff_t result = count_if(NamesVect.begin(), NamesVect.end(), MatchFirstChar) ;cout << "Number of elements that start with letter \"S\" = " << int(result) << endl ;

}

Page 147: 6 Continuacion C++

Ejemplo Completo#include <iostream>#include <fstream>#include <vector>#include <string>#include <algorithm> dict.txt

fwords.txtg

using namespace std;

template <class bid_it, class T>class nonAssocFinder {

esto es un diccionario esto es una frase

una salida

{bid_it _begin, _end;

public:nonAssocFinder(bid_it begin, bid_it end) : _begin(begin), _end(end) {}bool operator() (const T & word) { return binary_search(_begin, _end, word); }

frase

p () ( ) { y_ (_ g _ ) }};

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 diccionariocopy (istream_iterator<string>(dictFile), istream_iterator<string>(), back_inserter(dictionary)); py ( _ g ( ) _ g () _ ( y))sort (dictionary.begin(), dictionary.end()); // ordena el diccionario

remove_copy_if ( istream_iterator<string>(wordsFile),istream_iterator<string>(),

147147

g ()ostream_iterator<string>(cout, "\n"),nonAssocFinder<vector<string>::iterator, vector<string>::value_type>

(dictionary.begin(), dictionary.end()));}

Page 148: 6 Continuacion C++

AdaptadoresAdaptadoresClases que se basan en otras para implementar nueva funcionalidad.

Adaptadores de Contenedores: stack, queue, priority_queue.

#include <iostream>#include <stack>#include <stack>#include <vector>#include <list>#include <deque>#include <queue>

106

salida

#include <queue>using namespace std;

void main() {stack<int vector<int> > s1;

6531stack<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> less<int> > pq2(s1 c begin() s1 c end());priority_queue<int, vector<int>, less<int> > pq2(s1.c.begin(), s1.c.end());

while (!pq2.empty()) {

cout << pq2 top() << "\n";

148148

cout << pq2.top() << \n ;pq2.pop();

}}

Page 149: 6 Continuacion C++

AdaptadoresDe iteradores: inversos (reverse bidirectional iterator), de inserción

Adaptadores( _ _ ),

(back_insert_iterator, front_insert_iterator, insert_iterator)

lid#include <iterator>#include <algorithm>#include <vector>#i l d i t

salida1 2 3 4 5 El vector al reves es: 5 4 3 2 1 iterator pos = 4reverse_iterator rpos = 3

#include <iostream>int main( ) {

using std::vector;using std::cout;

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 );

t << "it t " << * << "\ "

149149

cout << "iterator pos = " << *pos << "\n";vector <int>::reverse_iterator rpos ( pos );cout << "reverse_iterator rpos = " << *rpos << "\n";

}

Page 150: 6 Continuacion C++

AdaptadoresAdaptadores

De funciones: negadores (neg1 y neg2), binders (bind1st, bind2nd), de punteros a funciones.

#include <functional>#include <algorithm>g#include <vector>#include <iostream>

i td0 1 2 3 4 5

salida

using namespace std;

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 co t << ec[i++] << " " )

150150

for ( int i = 0 ; i < 6 ; cout << vec[i++] << " " );}

Page 151: 6 Continuacion C++

EjercicioEjercicioUtilizando la STL realiza un programa que lea un ficheroUtilizando la STL, realiza un programa que lea un fichero con números 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 > 10void main() { // imprime todas los numeros > 10ifstream 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 diccionariocopy (nums.begin(), nums.end(), ostream_iterator<int>(cout,"\n"));

}

Page 152: 6 Continuacion C++

IndiceIndiceTipos y Declaraciones.FuncionesFunciones.Clases.Espacios de Nombres.Biblioteca Estándar (STL).

Herencia.C t l d AControl de Acceso.Polimorfismo.Herencia y Templates.y pPunteros a Miembros de Clase.Castings y RTTI.A bi ü d dAmbigüedad.Operadores.Herencia Múltiple.

152152152

pManejo de Errores.Entrada/Salida.

152

Page 153: 6 Continuacion C++

HerenciaHerenciaLa herencia afecta a variables y métodos pero no a constructoresLa herencia afecta a variables y métodos, pero no a constructores, destructores, operator=, o a elementos “friend”.

Llamada a constructores de superclases (en orden ascendente) y aLlamada a constructores de superclases (en orden ascendente) y a destructores (en orden descendente)

Por cada clase X y clase descendiente Y se permiten automáticamentePor cada clase X y clase descendiente Y se permiten automáticamente estas operaciones:

“punteroX”=“punteroY”“referenciaX”=“objetoY”referenciaX = objetoYX objX(objY) // constructor copia de X admite objetos Y

Ejemplos con: “E subclase de P”Ejemplos con: E subclase de Pclase E Empleado (nombre, edad, sueldo)clase P Persona (nombre, edad)

ét d i t l “ id t ()” l E l d P153153153

método virtual “void mostrar ()” en clase Empleado y Persona

Page 154: 6 Continuacion C++

Herencia

#include <iostream>

HerenciaEjemplo operator=

#include iostreamusing std::cout;class A {

int val;blipublic:

void f() {cout << "A::f()\n";}void operator= (int x) { val = x; }~A() { cout << "A::destructor\n";}A() { cout A::destructor\n ;}

};

class B : public A {}};

void main() {B b;

A::f()A::destructor

Consola

b;A a;a = 3;// b = 3; // inválidob f()

A::destructorA::destructor

154

b.f();// ¿funciona A a2(b);?

}

Page 155: 6 Continuacion C++

Herencia

#include <iostream>

HerenciaEjemplo 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); // inválido//B b; // inválidoA a(3);A a(3);B b=*static_cast<B *>(&a); // compila pero es dudoso...

// &a no es un B*}

155

Page 156: 6 Continuacion C++

Herencia Simple#include <iostream>#include <string>

Herencia SimpleEjemplo

using std::cout;using std::string;

class Persona {string nombre;int edad;

public:public:Persona(string name, int age) : edad(age), nombre(name) {

cout << "Constructor de Persona\n";}virtual void mostrar () {

cout << "Nombre: " << nombre << "\nEdad: " << edad << "\n";cout << Nombre: << nombre << \nEdad: << edad << \n ;}virtual ~Persona() {

156

cout<<"destructor de persona\n";}

};

Page 157: 6 Continuacion C++

Ejemploj pclass Empleado : public Persona{

long sueldoBruto;public:

Empleado(string name, int age, long sueldo) : Persona(name, age), sueldoBruto(sueldo) {

t "C t t d E l d \ "cout<< "Constructor de Empleado\n";}void mostrar(){P t ()Persona::mostrar();cout << "Sueldo Bruto " << sueldoBruto << "\n";

}~Empleado() {cout<<"destructor de empleado\n";}

}

ConsolaConstructor de Persona

};

void main(){P * E l d ("P d " 27 30000)

Constructor de EmpleadoConstructor de PersonaConstructor de EmpleadoNombre: MariaPersona * p = new Empleado("Pedro", 27, 30000);

Empleado * e = new Empleado("Maria", 30, 32000);Persona * p1 = e;p1->mostrar();d l t

Nombre: MariaEdad: 30Sueldo Bruto 32000destructor de empleado

157

delete p;delete e;

}

destructor de personadestructor de empleadodestructor de persona

Page 158: 6 Continuacion C++

HerenciaAcceso a un miembro de una clase:

Herencia

p.Punto::x=3;Equivalente a “p.x=3;”

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

Igual que un atributo normal, y también Punto::variableStatic=34;

Control de acceso a una clase: declaraciones public, private y protected para miembros de clase. Son accesibles:accesibles:

private: en la clase y “friends”public: desde cualquier sitio

“ ”protected: desde la clase y cualquier clase “X” descendiente (dentro de la clase “X” se permite el acceso a partir de objetos de tipo “X” o descendientes); también para “friends”

158158

Page 159: 6 Continuacion C++

Ejemplo protected#include <iostream>

Ejemplo protectedusing namespace std;class Base {public:

void setProtMemb( int i ) { m protMemb = i; }void setProtMemb( int i ) { m_protMemb i; }void Display() { cout << m_protMemb << endl; }

protected:int m_protMemb;void Protfunc() { cout << "\nAccess allowed\n"; }

} base;

class Deriv : public Base {class Deriv : public Base {public:

void useProtfunc() { Protfunc(); m_protMemb = 4; }} derived;

int main() {// base.m_protMemb; //error, m_protMemb is protectedbase setProtMemb( 0 ); // OK uses public access functionbase.setProtMemb( 0 ); // OK, uses public access functionbase.Display();derived.setProtMemb( 5 ); // OK, uses public access functionderived.Display();// b P f () // P f () i d

159159

// base.Protfunc(); // error, Protfunc() is protectedderived.useProtfunc(); // OK, uses public access function in derived class

}

Page 160: 6 Continuacion C++

Control de Acceso en HerenciaControl de Acceso en HerenciaComo otro miembro, una clase base se puede declarar comoComo otro miembro, una clase base se puede declarar como private, protected o public.

class B { /* */ };class B { / ... / };class X: public B { /* ... */ };class Y: protected B { /* ... */ };class Z: private B { /* ... */ };

La derivación publica hace la clase derivada un subtipo de la clase base y es lo más común. Es la derivación por defecto en structs.La derivación protegida y privada se usa para representar detalles de implementación.

Protected: cuando la clase derivada va a tener hijas a su vez, y laProtected: cuando la clase derivada va a tener hijas a su vez, y la clase base no tiene información de interfaz.Private (derivación por defecto en clases): Para restringir la interfaz de la clase base

160160

la clase base.

Page 161: 6 Continuacion C++

Control de Acceso en HerenciaEl especificador de acceso en herencia controla:

Control de Acceso en Herencia

el acceso a miembros de la clase base.la conversión de punteros y referencias de la clase derivada a la clase base.

Sea D una clase que hereda de B:qSi B se hereda como private:

Sus miembros públicos y protegidos se pueden usar sólo por funciones miembros y amigos de D. gSólo amigos y miembros de D pueden convertir de D* a B*.

Si B se hereda como protected:Sus miembros públicos y protegidos se pueden usar sólo por funciones miembros y p y p g p p yamigos de D y por funciones miembro y amigos de clases derivadas de D.Sólo amigos y miembros de D y amigos y miembros de clases derivadas de D pueden convertir de D* a B*.

Si B se hereda como public:Sus miembros públicos se pueden usar por cualquier función.Sus miembros protected se pueden usar por miembros y amigos de D y miembros y

i d l d i d d D161161

amigos de clases derivadas de D.Cualquier función puede convertir un D* a un B*.

Page 162: 6 Continuacion C++

Redefinición del AccesoUn miembro “x” de una clase A con privacidad “p1” en la clase A se

Redefinición del AccesoUn miembro x de una clase A con privacidad p1 en la clase A, se puede declarar con otra privacidad distinta “p2” con respecto a una clase hija B (heredada con privacidad “p3” con respecto a la clase “A”):)

class A { p1: x; p4: y;p4: y;

}class B : p3 A {

p2: A::x;p2: A::x;}

Esta especialización tiene prioridad respecto a la declarada por “p3”:p3 :

“p4” declara que B::y es A::y, y que tiene privacidad “p4” con respecto a clase B“p2” declara que B::x es A::x y que tiene privacidad “p2” con

162162

p2 declara que B::x es A::x y que tiene privacidad p2 con respecto a clase B

Page 163: 6 Continuacion C++

Ejemplo herencia publicEjemplo herencia publicclass A {private:

void main() {private:

int x;public:

int y1;

B b;b.y2=0; b.B::y2=0; // son equivalentesb.A::y1 = 3; // OK

int y2;int y3;

protected:int z;

b.A::y1 3; // OK

// b.y1=0; incorrecto// porque B::y1 es private// lint z;

};class B : public A {private:

// en clase B

// b.x=0; incorrecto // porque A::x es private

A::y1; // int A::y1; incorrecto// equivalente a// using A::y1;

// p q p// en clase A// b.A::x, b.B::x // son equivalentesA b // t// using A::y1;

int y3; // otro hueco // de memoria

A & a=b; // correctoA* p=&b; // correcto

}

163

// distinto a A::y3};

Page 164: 6 Continuacion C++

Ejemplo herencia private

l A {

Ejemplo herencia private

class A {private:

int x;public:

i tint y;protected:

int z;};l B i t A {

void main() {bclass B : private A {

public:A::z;// A::x; incorrecto

id f () {

B b;// b.y=0; incorrectob.z=0; // correcto// b.A::y=0; incorrectovoid f () {

B b;b.y=0; // OKA & a=b; // OKA* &b // OK

// b.A::y 0; incorrecto

// A & a=b; incorrecto// A* p=&b; incorrecto

A* p=&b; // OK// b.x=0; ilegal// b.z=3; ok

}}

}

164164

};

Page 165: 6 Continuacion C++

Ejemplo herencia protectedclass A {private:

Ejemplo herencia protectedvoid main() {

private:int x;

public:int y;

B b;b.z1=0;C c;

protected:int z1;int z2;

};

c.z1=0;// c.z2=0; incorrecto pero // correcto en clase C};

class B : protected A {public:

A::z1;

// c.y=0; incorrecto porque// “y” es protected en C

};class C : public B {

void f () {B b;

// A & a=b; incorrecto pero//correcto en clase C// A* p=&b; incorrecto peroB b;

A & a=b; // correctoA* p=&b; // correctoz2=3;

// A p &b; incorrecto pero// correcto en clase C// ¿es correcto B & bb = c; ?

}

165165

}};

}

Page 166: 6 Continuacion C++

PrivacidadPrivacidadSon mecanismos de encapsulamientoSon mecanismos de encapsulamiento.

a) Privacidad en miembros de clases: P i d i l l lPrivados: operaciones locales a clasesProtegidos: prohibido usar en clases no descendientes

b) H i i id db) Herencia con privacidad:El uso de herencia “private” y “protected” es una alternativa a los mecanismos de a).Herencia private: La clase base proporciona mecanismos de bajoHerencia private: La clase base proporciona mecanismos de bajo nivel, y no interesa como tipo. La clase derivada no tendrá clases hijas.Herencia protected: Parecido a private, pero abre la posibilidad de que la clase derivada tenga clases hijas.Permiten entregar clases a usuarios finales con redefinición de tipo de privacidad para los miembros que se quiera (por ejemplo con herencia “private” de su clase padre y modificadores “public” o “protected” para determinados miembros heredados)

166

)Un caso particular sería, en Java, la especificación “final” para una clase, que indica que no se pueden crear subclases

Page 167: 6 Continuacion C++

Control de Acceso

// La privacidad se declara con respecto a la

Control de AccesoTipos dinámicos

// La privacidad se declara con respecto a la// clase estática pero no dinámica. Ejemplo:class A {public:

virtual void f1() {cout << "En clase padre";}virtual void f2() {cout << "En clase padre";}

};class B : public A {class B : public A {private:

virtual void f1() {cout << "En clase hija";}A::f2;

};

void main() {A a;A a;B b;A & x = b; // la clase dinámica de x es “B”x.f1(); x.f2(); // ligadura dinámica. Métodos privados en clase hija

167

}

Page 168: 6 Continuacion C++

PolimorfismoPolimorfismoMétodos Virtuales

Método virtual“virtual” en declaración y opcionalmente y p“virtual” en las especializacionesTipos:Tipos:

Puro (“…=0” en declaración). • Una clase es abstracta si tiene al menos un método

virtual puro. • No se pueden crear instancias de clases abstractas.

Útil d l i t f• Útil para declarar interfaces.No puro (con código en todas las definiciones)

Li d táti /di á i168

Ligadura estática/dinámica

Page 169: 6 Continuacion C++

Polimorfismo¿Qué métodos se llaman?

PolimorfismoMétodos Virtuales

void main() {A a;B b;

#include <iostream>using std::cout;

{ B b;A* pa=&a;A* pb=&b;A& x=a;

class A {public:

virtual void f() {cout << "A\n";}

A& y=b;a.f(); // -> A::f()pa->f(); // -> A::f()pb->f(); // -> B::f()

};

class B : public A {bli pb >f(); // > B::f()

x.f(); // -> A::f()y.f(); // -> B::f()A* x1 = new C();

public:void f() {cout << "B\n";}

};

C* c = dynamic_cast<C*>(x1);A y1=*c;y1.f(); // -> A::f()(*c) f(); // -> C::f()

class C : public B {public:

void f() {cout << "C\n";}}

169

( c).f(); // > C::f()}

};

Page 170: 6 Continuacion C++

Polimorfismo¿Qué métodos se llaman?

PolimorfismoMétodos Virtuales

void main() {

A* x1 = new B();

#include <iostream>using std::cout;

{ A x1 = new B();C* c = dynamic_cast<C*>(x1);A y1=*c;y1.f();

class A {public:

virtual void f() {cout << "A\n";}

(*c).f(); // error!!}

};

class B : public A {blipublic:

void f() {cout << "B\n";}};

class C : public B {public:

void f() {cout << "C\n";}}};

Page 171: 6 Continuacion C++

Destructores virtualesDestructores virtuales#include <iostream>#include <string>using std::string;

class Persona {string nombre;int edad;int edad;

public:Persona(string name, int age) : edad(age), nombre(name) { /* … */ }virtual ~Persona() {/* */ } // destructor virtualvirtual ~Persona() {/ … / } // destructor virtual

};

class Empleado : public Persona {l ld B tlong sueldoBruto;

public:Empleado(string name, int age, long sueldo) : Persona(name, age), sueldoBruto(sueldo) { /* … */ }

~Empleado() {/*…*/}};

void main() {

171

void main() {Persona * p = new Empleado("Pedro", 27, 30000);delete p; // sin el destructor virtual no se llama al destructor de Empleado

}

Page 172: 6 Continuacion C++

EjerciciojLlamadas a métodos virtuales en destructores

class Persona {class Persona {string nombre;int edad;

public: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?empleado?¿Qué sucedería si mostrar() fuese virtual puro?

Page 173: 6 Continuacion C++

Llamadas a Métodos de Clases BaseLlamadas a Métodos de Clases Base

Llamadas entre métodos:Si Y es base de X, X puede llamar a un método de Y

di “Y ( )” ( á lmediante “Y::g(…)” (más general que “super.método(…)” en el caso de Java)

#include <iostream>using std::cout;

class A {class A {public: void f() {cout << "A\n";} };

class B : public A {p {public: void f() {cout << "B\n";}};

class C : public B {public: void f() { A::f(); cout << "C\n";}};

ConsolaLlamada a clase base

173

public: void f() { A::f(); cout << C\n ;}};

void main() { C c; c.f(); }AC

Page 174: 6 Continuacion C++

Herencia y Templatesy pHerencia de una clase template

template <int n, class T> template <int n, class T>class A {private:

T array[n];

class A {private:

T array[n];int dim;

public:A() : dim(n) {}

int dim;public:

A() : dim(n) {}A() : dim(n) {}};

t l t i t l T

A() : dim(n) {}};

l B bli A 3 i t {template <int n, class T>class B : public A<n, T>{

class B : public A<3, int>{

};};

void main() {void main() {

B b;void main() {B<3,int> b;

}

B b;}

Page 175: 6 Continuacion C++

Herencia y Templatesy pHerencia parametrizada

class A {private:

i t diint dim;public:

A(int n=0) : dim(n) {}}};

template <class Base>class B : public Base{

};

void main(){

B<A> b;}

Page 176: 6 Continuacion C++

Punteros a Atributosclass A {public:

int a;A() : a(5) {}A() : a(5) {}

};class B : public A {public:

int b;int b;B() : A(), b(3) {}

};

void main() {void main() {int A::* p;A a;A * pa = &a;p = &A::a; // sólo válido si a es públicop = &A::a; // sólo válido si a es públicoint ai = a.*p; // 5int ai2= pa->*p; // 5B b;B * pb = &b;B pb = &b;p = static_cast<int A::*>(&B::b); // casting explícito de int B::* a int A::*int bi = b.*p; // 3int vvv = a.*p; // sin sentido: -858993460int bi2 = pb >*p; // 3

176

int bi2 = pb-> p; // 3int B::* bbp = &A::a; // OKbi = b.*bbp; // 5 bi = a.*bpp; error

}

Page 177: 6 Continuacion C++

Punteros a Métodos#include <iostream>using std::cout;class A {

bli id f(i t ) { t "A f " "\ " }public: void f(int x) { cout << "A::f -> " << x << "\n"; }};class B : public A {

int x;blipublic:

B(int g=100) : x(g) {}void g(int y) { cout << "B::g -> " << y+x << "\n"; }

};id h(i t ) { t "h " "\ " }void h(int c) { cout << "h -> " << c << "\n"; }

void main() {void (A::* pfA)(int);A

A::f -> 1A::f -> 2

Consola

A a;A * pa = &a;pfA = &A::f;(a.*pfA)(1);( * fA)(2)

A::f > 2B::g -> 103B::g -> 104B::g -> -858993454

(pa->*pfA)(2);B b;B * pb = &b;pfA = static_cast<void (A::*)(int)>(&B::g);(b * fA)(3)

h -> 5A::f -> 3

(b.*pfA)(3);(pb->*pfA)(4);(a.*pfA)(6); // sin sentidovoid (* pfH)(int) = h;

fH(5)

177

pfH(5);void (B::* pfB)(int) = &A::f; // OK(b.*pfB)(3); // (a.*pfB)(3); incorrecto

}

Page 178: 6 Continuacion C++

Punteros a Métodos VirtualesPunteros a Métodos Virtuales

#include <iostream>using std::cout;class A {

blipublic:virtual void f(int x) { cout << "A::f -> " << x << "\n"; }

};

l B bli A {class B : public A {public:void f(int x) { cout << "B::f -> " << x << "\n"; }

};

void main() {void (A::* pfA)(int);B b;

Consola

B b;A a;A * pa = &b;pfA = &A::f;(a *pfA)(1);

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

178

(a.*pfA)(1);(pa->*pfA)(2);

}

Page 179: 6 Continuacion C++

CastingsCastings“tipo(expresion)”

Tipos primitivos: correcto-COMP, correcto-EJECObjetos. Para el casting “X(Y)”, si:

X desciende de Y: error-COMPX desciende de Y: error COMPY 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 clasecasting en la clase

class A {};

class C {};class A {};

};

class B : public A {};

A

class B : public A {public:

B () {}B( C & c ) {}}

void main() {B b;A a=A(b);

BB( C & c ) {}

};void main() {

C c;

179

A a=A(b);//B b2=B(a); // error

}

B b; b=B(c);

}

Page 180: 6 Continuacion C++

CastingsPunteros (castings al estilo C):

Tipos primitivos: correcto-COMP error-EJEC

CastingsTipos primitivos: correcto COMP, error EJECObjetos: correcto-COMP. Para un casting “(X*)Y*”, si:

Y desciende de X: correcto-EJECX desciende de Y: correcto-EJEC cuando el objeto apuntado por “Y*” es de tipo X d di tX o descendiente.En otros casos, error-EJEC

ReferenciasAnálogo a punterosAnálogo a punteros

Uso de dynamic_cast<>, o static_cast<>

class A {};class A {};class B : public A {public:

B () {}};

void main() { A * a = new B;

180

A a new B;B * b = (B*)a;

}

Page 181: 6 Continuacion C++

CastingsCastingsUso de “=“

Punteros:Tipos primitivos: válido si son del mismo tipop p pObjetos: “punteroclase=punteroClase Descendiente”;Descendiente ;“void*=cualquierPuntero”

I tIncorrecto:“variable-referencia-no-const=elemento-const”

181

Page 182: 6 Continuacion C++

Castings

#include <iostream>

CastingsEjemplos

#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()void main(){

E e; P p;E* pE;P* pP=&e;pE=(E*)pP; // OK// pE=pP; error-COMP

Consola

EE// pE=pP; error-COMP

pP->imprime(); (*pP).imprime(); ((P)e).imprime();

EPE

182

((P*)&e)->imprime(); }

Page 183: 6 Continuacion C++

#include <iostream>using std::cout;

CastingsEj l C l j i (i)using std::ostream;

class Complejo {private: double x; double y;

Ejemplo Complejos, version a (i)

private: double x; double y;public:

Complejo (double x, double y) : x(x), y(y) {}Complejo (double x) : x(x), y(0) {}// operador como método de objeto// operador como método de objetoComplejo 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() {void main() {Complejo c1(2,3), c2(4,5);Complejo s1=c1+c2;Complejo s2=c2+2; // casting implícito (inválido si el constructor es “explicit”cout << "La suma s1 es:" << s1; // 6+8i

183

cout << "La suma s1 es:" << s1; // 6+8icout << "La suma s2 es:" << s2; // 6+5i

}

Page 184: 6 Continuacion C++

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

Ejemplo Complejos, version b (i)class Complejo {private: double x; double y;public:

Complejo (double x, double y) : x(x), y(y) {}p j ( , y) ( ), 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 función

Complejo s(c1.x+c2.x,c1.y+c2.y);return s;

}}// si tuviéramos también la definición “Complejo::operator+(const Complejo&)const” se// producirían errores de ambigüedad

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 funcióncout << "La suma s1 es:" << s1; // 6+8icout << "La suma s2 es:" << s2; // 6+5i

184

cout << La suma s2 es: << s2; // 6+5icout << "La suma s3 es:" << s3; // 7+5i

}

Page 185: 6 Continuacion C++

Acceso a Tipo Dinámico (RTTI)Acceso a Tipo Dinámico (RTTI)

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

Tipo polimórfico:Tiene o hereda métodos virtuales

Acceso al tipo dinámico en C++En tipo polimórficosMediante “typeid(puntero|objeto)”

Devuelve una referencia a un objeto constante de la clase “type_info”

• “type_info::name()”• “bool type_info::operator==(const type_info &) “

Hacer “#include <typeinfo>”Para tipos no polimórficos devuelve tipos estáticos

185

Para tipos no polimórficos, devuelve tipos estáticos

Page 186: 6 Continuacion C++

Acceso a Tipo DinámicoAcceso a Tipo Dinámico#include <iostream>#include <iostream>#include <typeinfo>

class Base {public:

virtual void vvfunc() {}};

class Derived : public Base {};

using namespace std;int main() {

Derived* pd = new Derived;Base* pb = pd;cout << typeid( pb ) name() << endl; //prints "class Base *"cout << typeid( pb ).name() << endl; //prints class Base cout << typeid( *pb ).name() << endl; //prints "class Derived"cout << typeid( pd ).name() << endl; //prints "class Derived *"cout << typeid( *pd ).name() << endl; //prints "class Derived"

186

delete pd;}

Page 187: 6 Continuacion C++

Acceso a Tipo DinámicoAcceso a Tipo Dinámico

#include <iostream>#include <typeinfo>

using namespace std;using namespace std;

template < typename T > T max( T arg1, T arg2 ) {

cout << typeid( T ).name() << "s compared." << endl;return ( arg1 > arg2 ? arg1 : arg2 );

}

int main(){

typeid(int) == typeid(int&); // evalua a true}}

187

Page 188: 6 Continuacion C++

Castings C++Castings C++

Uso habitual en punteros o referenciasstatic_cast

Análogo al casting clásico de C, pero da errores en tiempoAnálogo al casting clásico de C, pero da errores en tiempo de compilación para conversiones imposiblesAplicable a cualesquiera tipos (no necesario polimórficos)No aplicable cuando no se garantice la conservación de p g“const”

dynamic_castEntre tipos polimórficos (A y B). Para una expresión de tipo p p ( y ) p ppuntero o referencia. Ejemplo para punteros:

“B* p=dynamic_cast<B*>(expresion);”Devuelve NULL si la conversión es imposibleP f i d ióPara referencias, se produce una excepción.

Más seguro, pero más ineficiente que el “static_cast”const_cast (Eliminar/Añadir “const” a expresiones)

i t t t (H i bit i t188

reinterpret_cast (Hacer conversiones arbitrarias entre tipos)

Page 189: 6 Continuacion C++

Castings C++#include <iostream>#i l d t i f

gEjemplo

#include <typeinfo>

class Base {public:

i t l id f () {}virtual void vvfunc() {}};class Derived : public Base {};

i tdusing namespace std;int main() {

Derived d;Derived & pd = d;B bBase b;Base & pb = b;try{

d d i t D i d& ( b)pd = dynamic_cast<Derived&>(pb);}catch(bad_cast bc){

t << " t t "cout << "cannot cast a "<< typeid(pb).name() << " to a " << typeid(pd).name() << "\n";

}}

Page 190: 6 Continuacion C++

EjercicioEjercicio#include <iostream>

• Dadas las clases Item y LineaPedido, implementa unasclases para el manejo de pedidos con la siguiente funcionalidad:

• Obtención del precio total.#include <iostream>#include <string>#include <vector>#include <map>#include <sstream>

Obtención del precio total.• Añadir línea de pedido.• Obtención de pedido por su ID.

•Un pedido puede ser simple o compuesto. Estos últimos estánt d did ( i l t )#include <sstream>

using namespace std;

class Item {

compuestos de pedidos (simples o compuestos).•Cada pedido tiene un ID único que se asigna automáticamente.

class Item {string nombre;double precio;

public:Item(string nombre double precio) : nombre(nombre) precio(precio) {}Item(string nombre, double precio) : nombre(nombre), precio(precio) {}double getPrecio() const {return precio;}string getNombre() const {return nombre;}

};

class LineaPedido {int num;Item * item;

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

};

Page 191: 6 Continuacion C++

EjercicioEjemplo código cliente

void main() {Item boligrafo("boligrafo", 3),

lapicero("lapicero" 2)

Ejemplo código cliente

lapicero( lapicero , 2),cuaderno("cuaderno", 10),folios("folios", 5),borrador("borrador", 1.5);

PedidoSimple ps1;ps1.anyadeLinea(10, &boligrafo).

anyadeLinea(3, &borrador).anyadeLinea(4 &lapicero);anyadeLinea(4, &lapicero);

PedidoCompuesto pc1;pc1.anyadePedido(&ps1);

Pedido #P1 precio= 85

Salida

PedidoCompuesto pc2;pc2.anyadePedido(&ps1);

pc1 anyadePedido(&pc2);

Pedido #P1, precio= 85Pedido #P2, precio= 42.5Pedido #P0, precio= 42.542.52pc1.anyadePedido(&pc2);

cout << pc1 << "\n" << pc1[1] << "\n" << ps1 << "\n"

2

<< ps1 << \n<< Pedido::getPedido("P0")->getPrecio() << "\n"<< Pedido::getPedido("P1")->numPedidos() << "\n";

}

Page 192: 6 Continuacion C++

SoluciónSoluciónclass Pedido{

static long int max_id;static map<string, Pedido *> pedidos;int id;int id;

public:// métodos virtuales purosvirtual double getPrecio() const = 0;virtual int numPedidos() const = 0;virtual int numPedidos() const = 0;Pedido() {

id = max_id++; // asigna el IDpedidos[getId()] = this; // almacena en diccionario

}}string getId() const {

stringstream s;s << "P" << id;return s str();return 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;

Page 193: 6 Continuacion C++

Soluciónclass PedidoSimple : public Pedido{

Soluciónp p {

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; }

};

Page 194: 6 Continuacion C++

Soluciónclass PedidoCompuesto : public Pedido {

Soluciónclass PedidoCompuesto : public Pedido {

vector<Pedido*> pedidos;public:

void anyadePedido(Pedido * p) {pedidos.push_back(p); }double getPrecio() const {double getPrecio() const {

double acum = 0.0;for ( vector<Pedido *>::size_type i = 0;

i < pedidos.size(); acum += pedidos[i++]->getPrecio() );acum += pedidos[i++]->getPrecio() );

return acum;}Pedido & operator[] (vector<Pedido*>::size_type idx) const {

if (idx < pedidos size()) return *pedidos[idx];if (idx < pedidos.size()) return 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();os << Pedido # << p.getId() << , precio << p.getPrecio();return os;

}

Page 195: 6 Continuacion C++

AmbigüedadAmbigüedadSobrecarga

D d l i d f ió ét dDos declaraciones de función o método son incompatibles (produciendo un error de compilación) si tienen el mismo nombre y suscompilación) si tienen el mismo nombre y sus argumentos son equivalentes.

Ejemplos de argumentos equivalentes: Renombramiento del parámetro.Argumento Obligatorio Argumento OpcionalArgumento “const” Argumento no “const”

Para un tipo X que es primitivo o clase:Para un tipo X que es primitivo o clase:• X const X

• X* X* const

195

Page 196: 6 Continuacion C++

Ambigüedad

Incompatibles:

AmbigüedadSobrecarga

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) {} void f (int* const p) {}void f (int p) {} void f (int const p) {}void f (Complejo* p) {} void f (Complejo* const p) {}void f () int f()

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

196void f (Complejo x) {} void f (Complejo & x) {}

Page 197: 6 Continuacion C++

Ambigüedad

S d t d d fi i i

AmbigüedadSobrecarga

Se pueden tener dos definiciones compatibles y producirse una llamada ambigua. Mensaje:

ambiguous call to overloaded function

Ejemplo:Ejemplo: Definiciones

• void f (Complejo x) {} void f (Complejo & x) {}( p j ) {} ( p j ) {}

LlamadaComplejo c;

197f(c);

Page 198: 6 Continuacion C++

Ambigüedad

Ejemplo 2

AmbigüedadConversión implícita y Sobrecarga

Ejemplo 2class A {public: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

Llamada: f(0);

Page 199: 6 Continuacion C++

AmbigüedadAmbigüedadParámetros variables y Sobrecarga

Ejemplo 3D fi i iDefiniciones

void f(int x){} void f(int x ...) {/*…*/}LlamadaLlamada

f(0);

Ejemplo 4j pDefiniciones

void f(int x=0){} void f(int x ...) {/*…*/}Llamada

f(0);

199

Page 200: 6 Continuacion C++

DesambiguaciónDesambiguación

SobrecargaVarias definiciones compatibles de funciones pglobales o métodos de una clase

Desambiguación:fPara varias definiciones compatibles y una

llamada no ambigua, existen reglas de d bi iódesambiguación

200

Page 201: 6 Continuacion C++

Desambiguación

Determinar las definiciones candidatas

DesambiguaciónReglas

Determinar las definiciones candidatasAquellas en donde son posibles las asignaciones mediante“=“ para los parámetros.

Dadas 2 definiciones candidatas D1 y D2, se dice queD1 es más específica que D2 si es posible lap q pasignación “ParametrosD2=ParametrosD1”

Ejemplo “void f(Empleado)” es más específica que “voidf(Persona)”f(Persona)

De entre las definiciones candidatas, buscar la másespecífica (si hay más de una sería una llamadaespecífica (si hay más de una sería una llamadaambigua).

201

Page 202: 6 Continuacion C++

DesambiguaciónDesambiguaciónExcepciones

Excepción 1:para las definiciones: p

D1: void f(int x){...}D2: void f(double y){...}( y){ }

se tendría que D1 es más específica que D2 yse tendría que D1 es más específica que D2 y viceversa, pero se considera D1 más específica por razones obvias. Por tanto: p

f(3) D1

202

Page 203: 6 Continuacion C++

Desambiguación

Excepción 2:

DesambiguaciónExcepciones

Excepción 2:

class B {}; class A : public B {};class C {

public: C(A a){}}};

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

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

203Ninguna es más específica que la otra, pero se considera D1 más específica priorizando la herencia frente al casting.

Page 204: 6 Continuacion C++

DesambiguaciónDesambiguación

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

A a; f(a) “void f(B)”

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

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

204

Page 205: 6 Continuacion C++

DesambiguaciónDesambiguaciónconst

// Definiciones compatibles (punteros):void d(Complejo * i){} // Definición 1

//void d(const Complejo * i){} // Definición 2

void main() {const Complejo c1;Complejo c2;d(&c1); // Definición 2 (la única candidata)( ); ( )d(&c2); // Definición 1 . De entre 2

// candidatas se busca la más específica}}

205

Page 206: 6 Continuacion C++

DesambiguaciónDesambiguaciónconst

// Definiciones compatibles (referencias):void d(Complejo & i){} // Definición 1void d(const Complejo & i){} // Definición 2

void main() {const Complejo c1;Complejo c2;d(c1); // Definición 2 (la única candidata)( ); // ( )d(c2); // Definición 1 . De entre 2

// candidatas se busca la más específica}}

206

Page 207: 6 Continuacion C++

Desambiguación

// D l f l ét d d l i l

Desambiguaciónconst

// De alguna forma, los métodos de clases equivalen // a funciones globales con un parámetro más: “this”class A {public:p

void f () { // Definición 1// Siempre se cumple que "A* const this"

};void f () const {void f () const {// Ahora además se cumple que "const A* this"

};};

void main(int argc, char* argv[]) {A a1;a1 f(); // Definición 1 (de entre 2 candidatos)a1.f(); // Definición 1 (de entre 2 candidatos)const A a2;a2.f(); // Definición 2 (de entre 1 candidato)

}

207

Ejemplo:iterator vector::begin(); const_iterator vector::begin() const;

Page 208: 6 Continuacion C++

Desambiguación

Casos:

Desambiguaciónpolimorfismo

Casos:Sobrecarga (overloading)Sobreescritura (overriding)

Entre 2 clases relacionadas por herencia: Métodos virtuales:

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

Métodos no virtuales:Se puede tener 2 definiciones incompatibles

Pasos para ejecutar “objeto.método” (ejemplos en “sobrecarga.cpp”):

En tiempo de compilaciónEn tiempo de compilaciónDesambiguación de sobrecarga en la clase de “objeto”

En tiempo de ejecuciónSi el método es virtual se considera la definición en la clase dinámica de

208

Si el método es virtual, se considera la definición en la clase dinámica de “objeto”

Page 209: 6 Continuacion C++

DesambiguaciónDesambiguaciónMétodos 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 compilaciónb.f(1);b.C::f(2);const B bc;

ConsolaB::fC::f -> 2

209

//bc.f(3); // error de compilaciónbc.C::f(3);

}

C::f const -> 3

Page 210: 6 Continuacion C++

#include <iostream> Desambiguaciónusing std::cout;using std::endl;

class B;

Desambiguaciónpolimorfismo: 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;}virtual void f (B x) {cout << Funcion f (B ) en clase A << endl;}

};class B : public A {public:void f (A* x) { cout << "Funcion f (A*) en clase B" << endl;}void f (A x) { cout << Funcion f (A ) en clase B << endl;}void f (B* x) {cout << "Funcion f (B*) en clase B" << endl; }

};void main() {B b;B b;A a;A & x = b;a.f(&a); a f(&b); Funcion f (A*) en clase A

Consolaa.f(&b);x.f(&a);x.f(&b);x.f(&x);b f(&a);

Funcion f (A*) en clase AFuncion f (B*) en clase AFuncion f (A*) en clase BFuncion f (B*) en clase BFuncion f (A*) en clase Bb.f(&a);

b.f(&b);cout << "Final";

}

Funcion f (A ) en clase BFuncion f (A*) en clase BFuncion f (B*) en clase B

Page 211: 6 Continuacion C++

Funciones VirtualesFunciones VirtualesRetorno 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;

211

A * a = d->getA();}

Page 212: 6 Continuacion C++

Funciones VirtualesFunciones VirtualesRetorno covariante

class Shape {public:virtual ~Shape() { }virtual void draw() = 0;virtual void move() = 0;...virtual Shape* clone() const = 0; // Uses the copy constructorvirtual Shape* create() const = 0; // Uses the default constructor};

class Circle : public Shape {public:Circle* clone() const; // Covariant Return Types; see belowCircle* create() const; // Covariant Return Types; see below...

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

};

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

Shape* s3 = s.create();...delete s2; // You need a virtual destructordelete s3;

212

}

Page 213: 6 Continuacion C++

Desambiguación

// motivado por la existencia de herencia múltiple

DesambiguaciónOcultación

// motivado por la existencia de herencia múltiple class A {public:

id f (i t) {}void f (int) {};};class B : public A {public:

void f () {};};class C : public B {};

void main() {() {C c;// c.f(3); errorc A::f(3);

213

c.A::f(3);c.f(); // correcto

}

Page 214: 6 Continuacion C++

EjercicioEjerciciol Cl kTi bli S bj t {class ClockTimer : public Subject {

public:ClockTimer();virtual int GetHour();tua t Get ou ();virtual int GetMinute();virtual int GetSecond();void Tick() {// update internal time-keeping state// ...Notify();

}}};

Diseña una serie de clases que permitan que una instancia de ClockTimer pueda actualizar un número arbitrario de instancias de relojes de distinto tipo(analógicos, digitales, etc.). Cuando los distintos relojes reciben una invocación al método Update(), deben actualizarse (llamada a Draw())

Page 215: 6 Continuacion C++

SoluciónSoluciónPatrón de diseño Observerclass Subject;class Observer {public:virtual ~ Observer();virtual void Update(Subject* theChangedSubject) = 0;p ( j g j ) ;

protected:Observer();

};class Subject {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:S bj t()Subject();

private:List<Observer*> *_observers;

};

Page 216: 6 Continuacion C++

Soluciónclass DigitalClock: public Widget, public Observer {

public:public:

DigitalClock(ClockTimer* s) : _subject(s) { _subject->Attach(this); }

virtual ~DigitalClock(){_subject->Detach(this);}

virtual void Update(Subject* changed) {if (changed == subject) Draw();}virtual void Update(Subject changed) {if (changed == _subject) Draw();}

virtual void Draw(); // defines how to draw the digital clock

private:

ClockTimer* subject;ClockTimer _subject;

};

void DigitalClock::Draw () {

// get the new values from the subject// g 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();

// ...

};

Page 217: 6 Continuacion C++

OperadoresOperadoresNo se pueden definir operadores nuevosNo se pueden definir operadores nuevos.

Al h b ti l lAl hacer sobrecarga, se mantienen las reglas de precedencia del operador.

Se pueden definir como funciones globales o ét dcomo métodos:

Necesario definirlos de las 2 formas en caso de necesidad de conmutatividadnecesidad de conmutatividad

Algunas llamadas pueden ser ambiguas

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

Page 218: 6 Continuacion C++

class A {public: Operadoresint* v;A(int* v) : v(v) {}int& operator[] (int i) {

return v[i];

OperadoresEjemplo

return v[i];}

};// Al menos un parámetro debe ser un objetoint operator+(int x, A & a) {return 0;}

void main() {int numeros[2]={1 2};int numeros[2]={1, 2}; A a(numeros); int x; x=3+a; x=operator+(3,a); // es equivalentex=operator + (3,a); // equivalente tambiénx=3-4;// x=operator-(3 4); ERROR// x operator (3,4); ERRORnumeros[0]=3;// numeros.operator[](0)=3; ERRORa[0]=4;

218

a.operator[](0)=4; // equivalente }

Page 219: 6 Continuacion C++

Operadores

l F h {

OperadoresEjemplo

class 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[]) {void main(int argc, char* argv[]) {

Fecha f;//f=f+3; llamada ambiguaf=operator+(f,3);

219

f=f.operator+(3);f=3+f; // correcto

}

Page 220: 6 Continuacion C++

Algunos Operadores ImportantesAlgunos Operadores Importantes

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

Operadores “=“ y “==“Operador “==“ definido como función globalOperador == definido como función global

Entre punteros:• Tipos primitivos: del mismo tipo• Objetos: del mismo tipo o relacionados por herenciaObje os de s o po o e ac o ados po e e c a

Entre cualesquiera tipos primitivos no punterosNo definido por defecto en cualquier clase

Operador “=“ definido por defecto como método de objeto para cualquier clase

N d fi ibl f ió l b l220

No definible como función global

Page 221: 6 Continuacion C++

Operator ==#include <iostream>using std::cout;

p

class B {int h;

public: B(int x = 0) : h(x) {cout<<"const B\n";}B(int x = 0) : h(x) {cout<< const B\n ;}int getVal() const { return h; }

};

class A {int n;

public: A(int x=0) : n(x) {cout<<"const A\n";}A(int x=0) : n(x) {cout<< const A\n ;}bool operator == (B & b) { return n == b.getVal(); }// Puede definirse como método o como función global

};

void main() {A a, a2;B b;a == b ? cout << "iguales\n" : cout << "distintos\n";

221

a == b ? cout << iguales\n : cout << distintos\n ;&a == &a2 ? cout << "punteros iguales\n" : cout << "punteros distintos\n";// &a == &b ? cout << "punteros iguales\n" : cout << "punteros distintos\n"; error

}

Page 222: 6 Continuacion C++

Lista de OperadoresLista de Operadores

SobrecargablesSobrecargablesUnarios (uso opcional de paréntesis en argumento)

+, -, ++, --, !, ~ (de bit), &(dirección), sizeof, (tipo)Binarios

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

Binarios (de asignación)Binarios (de asignación)=, +=, -=, *=, /=, %=, >>=, <<=, &=, |=, ^=

Sobrecargables (con precaución)“->”, “[]”, “()” llamada a función, new, new [], delete, delete []

No sobrecargables“.”, “::”, “? :”. , :: , ? :

Ejemplos: “complejos.cpp”, “cadenas.cpp”

222

Page 223: 6 Continuacion C++

Ejemplo#include <iostream>

using std::ostream; Ejemplousing std::ostream;using std::ios;using std::cout;

class complejo {private:double real, imag;

public:complejo() : real(0), imag(0) {};

l j (d bl d bl i 0 0) l( ) i (i ) {}complejo(double re, double im=0.0) : real(re), imag(im) {}complejo(const complejo & c) : real(c.real), imag(c.imag) {}

// Sobrecarga de operadores aritméticoscomplejo operator+ (const complejo&) const;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 asignación, no se puede definir como operador

globalgoperator 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 unarioscomplejo 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 comparación//bool complejo::operator== (const complejo&) const; // Alternativa como operador de objetofriend bool operator!= (const complejo&, const complejo&);friend ostream& operator<< (ostream&, const complejo&); // Sobrecarga del operador de inserción en el flujo de salida// Una funcion global que se comportaría como el operador =

223

// Una funcion global que se comportaría como el operador = friend complejo & asignar (complejo&, const complejo&);

};

Page 224: 6 Continuacion C++

Ejemplocomplejo complejo::operator+ (const complejo &a) const {// operador miembro + sobrecargado

Ejemplop j p j p ( 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);complejo resta (real a.real, imag a.imag);return resta;

}complejo& complejo::operator= (const complejo &a) {// operador miembro de asignación sobrecargado

real = a.real;i iimag = a.imag;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 ++ prefijocomplejo & complejo::operator ++ () {// operador unario ++ prefijo

real++; imag++;return *this;

}complejo complejo::operator ++ (int x) {// operador unario ++ postfijo

real++; imag++;

224

real++; imag++;return *this;

}

Page 225: 6 Continuacion C++

Ejemplobool operator== (const complejo& a, const complejo& b) {// operador friend de test de igualdad sobrecargado

Ejemploreturn (a.real==b.real && a.imag==b.imag);

}// operador friend de test de desigualdad sobrecargadobool operator!= (const complejo& a, const complejo& b) {return (a real!=b real || a imag!=b imag);return (a.real!=b.real || a.imag!=b.imag);

}ostream& operator << (ostream& co, const complejo &a) {// operador friend << sobrecargadoco << a.real;long fl = co.setf(ios::showpos);o g 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 globalc1.real = c2.real;c1.imag = c2.imag;return c1;

}}

void main(){

complejo c1(2, 3), c2 = 4;

225

complejo c1(2, 3), c2 4; complejo c3 = c1+c2;cout << c3 << ‘\n’ << (c1==c2);

}

Page 226: 6 Continuacion C++

Operator <<#include <iostream>using namespace std;class Figura {public: Operator <<virtual ostream& put (ostream &s) const = 0;virtual ~Figura(){} // no se permiten destructores virtuales puros

};class Circulo : public Figura {

double cx cy rad;double cx, cy, rad;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";return s circulo{[ cx , cy ], rad 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";return s << rect{[ << x1 << , << y1 << ], [ << x2 << , << y2 << ]}\n ;}~Rectangulo() {}

};inline ostream& operator << (ostream& s, const Figura& f) { return f.put(s);}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); circulo{[10 10] rad=0 5}

Consola

figs[1] = new Rectangulo(10, 10, 12, 12);cout << *figs[0] << *figs[1];delete [] figs;

}

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

Page 227: 6 Continuacion C++

Operator [ ]

#include <iostream>#include <string>#include <vector>using namespace std; Operator [ ]class Assoc {

struct Pair {string name;double val;P i ( t i "" d bl 0) ( ) l( ) {}Pair(string n="", double v=0) : name(n), val(v) {}

};vector<Pair> vec;Assoc(const Assoc&); // privado para evitar copiasAssoc& operator=(const Assoc&); // privado para evitar copias

public:Assoc() {}const double& operator[] (const string&);double& operator[](string&);void print all() const;void print_all() const;

};double& Assoc::operator [](string &s) {

for (vector<Pair>::iterator p=vec.begin(); p!=vec.end(); ++p)if (s==p->name) return p->val;

ec p sh back(Pair(s 0))vec.push_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;string buf;Assoc vec;while (cin>>buf) vec[buf]++;vec.print_all();

}

Page 228: 6 Continuacion C++

Operador >Operador ->

Su uso principal es crear#include <iostream>

class Ptr {

Su uso principal es crear “smart pointers”: objetos que actúan como punteros y

h l dstruct X { int m; } x;public:X * operator->();

que hacen algo cada vez que se accede a un miembro.

};

Ptr::X * Ptr::operator->() {t &

Ej.: cargar datos desde disco si los datos no estánreturn &x;

}

void main() {

disco si los datos no están en memoria.

void main() {Ptr p;p->m=5;//int n = p >; // error

Debe ser un miembro de la clase, y debe retornar un puntero a un objeto al que //int n = p->; // error

}

p j qse le pueda aplicar ->.

Page 229: 6 Continuacion C++

#include <iostream>#include <string>

Operador >using namespace std;

struct Rec{

i

Operador ->string name;

};

class Rec_ptr{{

const char * identifier;Rec * in_core_address;

public:R t ( t h * ) id tifi ( ) i dd (0) {}Rec_ptr(const char * p) : identifier(p), in_core_address(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);t i ddreturn in_core_address;

}

void update(const char* s){R t ( ) // bt R tRec_ptr p(s); // obtener Rec_ptr para sp->name="Pedro";

}

Page 230: 6 Continuacion C++

Operadores de casting#include <iostream>#include <string>#include <sstream>using std::string; Operadores de castingusing std::string;using std::stringstream;using std::cout;class Nam {string s;string s;

public:Nam (string & st) : s(st) {}operator string() const { return s;}

};};

class Num {int x;

public:public:Num (int n) : x(n) {}operator int() const { return x;}operator Nam() const {

stringstream st;stringstream st;st << x; return st.str();

}};};void main() {

Num n(8);Nam nam(string(""));int x = n;

230

int x = n;nam=n;cout << string(nam);

}

Page 231: 6 Continuacion C++

Operador ++ #include <iostream> pPrefijo y Sufijo

using std::cout;using std::endl;

class A {class A {int a;

public:A(int n=0) : a(n) {}A& operator++ () {

cout << "prefijo\n"; ++a;return *this;return this;

}A& operator++ (int n) {

cout << "sufijo\n"; ++a;return *this;

}};};

void main() {A a(6), b;

231

b = ++a; // b = 7;b = a++; // b = 8; a = 8; ojo con la precedencia!!

}

Page 232: 6 Continuacion C++

#include <iostream>#include <string>#include <sstream> Operadores#include <sstream>

using namespace std;

OperadoresEjemplo

struct A { // clase con todos los miembros públicosvirtual A& operator++ () = 0; virtual A& operator+ (A &) = 0; virtual string comoString () = 0;virtual string comoString () = 0;

};

struct B : public A {int x;B () {}B (int x) : x(x) {}B& operator+ (A & a) {B& operator+ (A & a) {

B* b=new B(); // memoria dinámica a liberarif (B* ba = dynamic_cast<B*>(&a)) {

b->x=x+ba->x;}return *b;

}

232

...

Page 233: 6 Continuacion C++

OperadoresOperadoresEjemplo

...B& operator++ () {

x++;return *this;

}string comoString () {

t i tstringstream s;s << x;return "B[" + s.str() + "]";

}}};ostream& operator<< (ostream& co, A & a) {

return co << a comoString();return co << a.comoString();}...

233

Page 234: 6 Continuacion C++

Operadoresvoid main() {

OperadoresEjemplo

B b1(3), b2(4);cout << "Valores: " << b1 << "," << b2 << endl;++b1; ++b2;b2;cout << "Valores despues: " << b1 << ","

<< b2 << endl;A & a = b1+b2;

dlcout << "Suma: " << a << endl;// Equivalente a lo siguiente (ligadura dinámica):// B suma =dynamic_cast<B&>(a);// cout << "Suma:" << suma << endl;// cout Su a su a e d ;delete &a;

}Resultado

Valores: B[3],B[4]Valores despues: B[4],B[5]Suma: B[9]

234

Suma: B[9]

Page 235: 6 Continuacion C++

Ejemplo Operadores#include <iostream>#include <string>

using std::strcpy; j p pUna clase String

using std::strcmp;using std::ostream;using std::istream;using std::string;using std::cin;using std::cin;using std::cout;

class String {struct Srep; // para almacenar el string en sí, compartido por varios Stringstruct Srep; // para almacenar el string en sí, compartido por varios StringSrep * rep;class Cref; // clase ayuda para implementar el operador []

public:class Range {}; // para excepciones

String(); // String x = ""String(const char *); // String x = "abc"String(const String&); // String x = other_string (semántica de valor)String& operator=(const char *); // x = "abc"String& operator=(const char *); // x = "abc"String& operator=(const String&); // x = other_string (semántica de valor)~String();

// Operadores de acceso// Operadores de accesovoid check(int i) const;char read(int i) const;void write(int i, char c);Cref operator[](int i);

235

char operator[](int i) const;int size() const;// concatenación y funciones útiles

Page 236: 6 Continuacion C++

String operator+= (const String&);String operator+= (const char *);friend ostream& operator<< (ostream&, const String&);friend istream& operator>> (istream&, String&); Ejemplofriend 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};

String operator+(const String&x, const String&y);String operator+(const String&x, const char *s);

struct String::Srep{struct String::Srep{char *s; // puntero a elementosint sz; // numero de caracteresint n; // cuenta de referenciasSrep(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);return new Srep(sz, s);

}void assign(int nsz, const char * p) {

if (sz!=nsz) {delete [] s;sz = nsz;sz = nsz;s = new char[sz+1];

}strcpy(s, p);

}

236

private: // para prevenir copiaSrep (const Srep&);Srep& operator=(const Srep&);

};

Page 237: 6 Continuacion C++

class String::Cref{friend class String;String & s; Ejemploint i;Cref(String &ss, int ii) : s(ss), i(ii) {}Cref(const Cref& r) : s(r.s), i(r.i) {}Cref();

public:

Stringpublic:

operator char() const { s.check(i); return s.read(i); } // devolver valorvoid operator=(char c) {s.write(i, c); } // cambiar valor

};

String::String() { // el string vacío es el valor por defectoString::String() { // el string vacío es el valor por defectorep = new Srep(0, "");

}

String::String(const String& x) { // constructor copiax.rep->n++;rep = x.rep; // compartir la representación

}

String::~String() {String:: String() {if (--rep->n==0) delete rep;

}

String& String::operator= (const String& x) { // asignación copiax rep >n++; // antes por si "st=st"x.rep->n++; // antes por si st=stif (--rep->n==0) delete rep;rep = x.rep;return * this;

}

237String::String(const char * s){

rep = new Srep(strlen(s), s);}

Page 238: 6 Continuacion C++

String& String::operator = (const char * s){if (rep->n==1) rep->assign(strlen(s), s); // reciclar Srep Ejemploelse {rep->n--;rep = new Srep(strlen(s), s);

}

Stringreturn * this;

}

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;

t t ()238

s=st.c_str();return i;

}

Page 239: 6 Continuacion C++

Ejemplo

// ----------------------------------------------------------------------------------------------------// d

String// user code// ----------------------------------------------------------------------------------------------------

String f(String a, String b){{

a[2] = 'x';char c = b[3];cout << "en f: " << a << ' ' << b << ' ' << c << '\n';return b;return b;

}

void main() {String x y;String x, y;cout << "introduce 2 cadenas\n";cin >> x >> y;cout << "la entrada fue " << x << ' ' << y << '\n';String z = x; // constructor copiaString z = x; // constructor copiay=f(x, y);if (x != z) cout << "x corrupto";x[0]='!';if (x==z) cout << "la escritura fallo\n";

239

if (x==z) cout << la escritura fallo\n ;cout << "exit: " << x << ' ' << y << ' ' << z << ' ' <<'\n';

}

Page 240: 6 Continuacion C++

Herencia MúltipleHerencia Múltiple

Sintaxis: class X : [virtual] [tipo_acceso] clasePadre1, [virtual] [tipo acceso] clasePadre2 { };[virtual] [tipo_acceso] clasePadre2 …{…};

• Tipo_acceso: “public”, “private” y “protected” Acceso habitual: “public”Acceso habitual: publicAcceso por defecto: “private”

Posibles accesos “ambiguos”Posibles accesos ambiguos

240

Page 241: 6 Continuacion C++

Ejemplo SencilloEjemplo Sencillo

class A {public:

A(){cout<<"A";}A(){cout<< A ;}};class B {

public: B(){cout<<"B";}B(){cout B ;}

};

class C : public A, public B {public: pub c:

C(){cout<<"C";}};// Equivalente a:// class C : public A, public B // p , p// {public: C() : A (), B () {cout<<"C";}};

void main() {C c; // Resultado:ABC

241

; //}

Page 242: 6 Continuacion C++

Ejemplos Herencia MúltipleEjemplos Herencia Múltiple

Ej lEjemplosVentana

V t C MVentanaConMenu• VentanaConMenuYBorde

VentanaConBordeVentanaConBorde• VentanaConMenuYBorde

PersonaEmpleado

• EmpleadoCasado (con descuento por ser empleado y estar casado)estar casado)

PersonaCasada• EmpleadoCasado

242

Page 243: 6 Continuacion C++

Herencia Múltiple

class Task{

Herencia MúltipleTipos

class Task{};

class Displayed{class Displayed{};

class Satellite : public Task public Displayed {class Satellite : public Task, public Displayed {};

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*

}

Page 244: 6 Continuacion C++

Herencia MúltipleHerencia MúltipleFunciones 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 pending(); // se sobreescribe Task::pending()void draw(); // se sobreescribe Displayed::draw()

};

Page 245: 6 Continuacion C++

Llamadas Constructores/DestructoresLlamadas Constructores/DestructoresLos constructores se llaman en el orden en el que se especifican en la herencia Los destructores en orden inversola herencia. Los destructores en orden inverso.

#include <iostream>using std::cout;using std::cout;class Task{public:

Task() {cout << "Const. Task\n"; }virtual ~Task() {cout << "Dest Task\n"; }virtual Task() {cout << Dest. Task\n ; }

};class Displayed{public:

Displayed() {cout << "Const Displayed\n"; } Const TaskConsola

Displayed() {cout << Const. Displayed\n ; }virtual ~Displayed() {cout << "Dest. Displayed\n"; }

};class Satellite : public Task, public Displayed {public:

Const. TaskConst. DisplayedConst. SatelliteDest. Satellitepublic:

Satellite() {cout << "Const. Satellite\n"; }virtual ~Satellite() {cout << "Dest. Satellite\n"; }

};void main(){

Dest. DisplayedDest. Task

void main(){Satellite * s = new Satellite;delete s;

}

Page 246: 6 Continuacion C++

AmbigüedadAmbigüedadBases con miembros que se llaman igualclass 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 “ocultación” recíprocac D::f(); // OK

246

c.D::f(); // OK}

Page 247: 6 Continuacion C++

Ambigüedad#include <iostream>using std::cout; Ambigüedad

Declaraciones usingclass A{public:

void f(int) {cout << "A::f(int)\n"; }id f( h ) { t "A f( h )\ " }void f(char) {cout << "A::f(char)\n"; }

//...};

l B{class B{public:

void f(double){cout << "B::f(double)\n"; };//...

}};

class AB : public A, public B {public:

i A f Consolausing A::f;using B::f;void f(double) {cout << "AB::f(double)\n"; }void f(char) {cout << "AB::f(char)\n"; }

}

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

};

void main(){AB a;

f(1)a.f(1);a.f('a');a.A::f('b');

}

Page 248: 6 Continuacion C++

Clases Base ReplicadasClases Base Replicadas

C l h i últi l í ibl tCon la herencia múltiple sería posible tener una clase base replicada.

Link

Task Displayed Task

Link

Displayed

Link

Satellite

Link estaría dos veces en Satellite

Satellite

Link estaría dos veces en Satellite.

Page 249: 6 Continuacion C++

Clases Base ReplicadaspHerencia virtual

class Storable{public:

Storable(string *);virtual void read() = 0;virtual void write() = 0;virtual ~Storable();

private:string fileStore;Storable (const Storable&);Storable & operator= (const Storable&);

}

Receiver

};class Transmitter: public virtual Storable {public:void write();//

Transmitter

Storable

Radio//...

};class Receiver: public virtual Storable {public:

id it ()void write();//...

};class Radio: public Transmitter, public Receiver {

blipublic:void write();//...

};

Page 250: 6 Continuacion C++

Herencia VirtualHerencia VirtualUna herencia virtual para un conjunto de clases h (hij d l X) ifihermanas (hijas de una clase X) especifica que no se repliquen las componentes heredadas de X para un objeto perteneciente a una clase descendiente común j pde 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 más abajo en lapor el constructor de la clase derivada más abajo en la jerarquía.

250Permite desambiguación en acceso a componentes heredadas (ver “Ejemplo desambiguación virtual”)

Page 251: 6 Continuacion C++

Ejemplo Herencia VirtualEjemplo Herencia Virtualtemplate<class Elem class Traits> class basic iostreamtemplate<class _Elem,class _Traits> class basic_iostream

: public basic_istream<_Elem,_Traits>,public basic_ostream<_Elem, _Traits>

template<class _Elem,class _Traits>class basic_istream: virtual public basic_ios<_Elem, _Traits>

template<class _Elem,class _Traits> class basic_ostream: virtual public basic ios< Elem, Traits>p _ _ , _

typedef basic_iostream<char,char_traits<char>> iostream;typedef basic istream<char char traits<char> > istream;typedef basic_istream<char, char_traits<char> > istream;typedef basic_ostream<char, char_traits<char> > ostream;typedef basic_ios<char, char_traits<char> > ios;

251

Page 252: 6 Continuacion C++

Ejemplo Herencia Virtualclass A {p blic A() {co t << "A" }}

Ejemplo Herencia Virtualclass A {public: A() {cout << "A";}};class B : virtual public A

{public: B() {cout << "B";}};class D : virtual public A

{public: D() {cout << "D";}};class E : public A {public: E() {cout << "E";}};class C: public B, public D, public E

{public: C() {cout << "C";}};

void main(int argc, char* argv[]) {C c;

// Resultado:ABDAEC// Resultado:ABDAEC// Si ninguna herencia fuera // virtual --> Resultado:ABADAEC

}252

}

Page 253: 6 Continuacion C++

Ejemplo Desambiguación VirtualEjemplo Desambiguación Virtualclass A {public: int a; void f(){}};class B : public A {};class D : public A {};class C: public B, public D {};

void main() {C c;;// c.a=7; error: "ambiguous access of a"// c.a=7; correcto si la B y D son

// hermanas virtuales hijas de A// hermanas virtuales hijas de Ac.A::a=7; // OK, se cambia el de B::A.c.D::a=8; // OKA a;A a; // A a=c; error: "ambiguous conversions

// from C to 'const A &'"// i l

253

// A a=c; correcto si la B y D son //hermanas virtuales hijas de A

}

Page 254: 6 Continuacion C++

Herencia Virtual y Métodos VirtualesHerencia Virtual y Métodos Virtuales

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

Algoritmo de desambiguación para g g p“objeto.método” (método virtual)

Entre la clase estática de “objeto” y la clase dinámica (que siempre es descendiente de ladinámica (que siempre es descendiente de la estática), se permiten sólo “overriding” en una cadena lineal de clases

254

Page 255: 6 Continuacion C++

EjemplosEjemplos

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

Si h i i t lSin herencia virtual:C c; c.f llamada ambigua (no sabe si aplicar D::f o B::f)o B::f)

• Se podría añadir “using D::f” en la clase C.

Con herencia virtual:Error en la declaración de la clase “C”:

• “C: ambiguous inheritance of ‘void A::f’”

255

Page 256: 6 Continuacion C++

EjemplosEjemplos

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

Sin herencia virtual:C c; c.f llamada ambigua (no sabe si aplicar B::A::f o D::f).P d í C “ i D f ”Podríamos poner en C “using D::f;”

Con herencia virtual:Dominancia: D::f sobreescribe a A::fC c; c.f(); A & a=c; a.f();

256

• Ejecución doble de “D::f”

Page 257: 6 Continuacion C++

Cross Delegation#include <iostream>using std::cout;

class Base{ Cross-Delegation{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(){

ConsolaDer1::foo()Der2::bar()(){

Join * p1 = new Join;Der1* p2 = p1;Base* p3 = p1;

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

p1->foo();p2->foo();p3->foo();

}

Der2::bar()

Page 258: 6 Continuacion C++

IndiceIndice

Ti D l iTipos y Declaraciones.Funciones.Clases.Espacios de Nombres.Biblioteca Estándar (STL).Herencia.Manejo de Errores.

Errores de ejecución terminación delErrores de ejecución, terminación del programa.Excepciones

258258258

Excepciones.Entrada/Salida. 258

Page 259: 6 Continuacion C++

Errores de EjecuciónErrores de Ejecuciónclass A {{public:

int x;};class B : public A {public:

int y;};void main(int argc, char* argv[]) {

A* p;// ó// p->x=3; error de ejecuciónA a;B* q=(B*)&a; // en Java error de ejecución// > 7 d j ió// q->y=7; error de ejecución

}Error de ejecución:

El programa finaliza mostrando una

259

El programa finaliza mostrando una ventana de diálogo

Page 260: 6 Continuacion C++

Finalización del Programa

“ it(i t )”

Finalización del Programa

“exit(int x)”Finalización normal mostrando ventana de comandoscomandos

• El valor de esta finalización es x, que suele ser 0

“terminate()”terminate() Finalización de un programa mostrando una ventana de diálogo (error de ejecución)Si una excepción no se captura o se produce un error de ejecución, se llama a “terminate()”No se produce liberación de memoriaNo se produce liberación de memoria automáticaFinalización análoga haciendo “abort()”

260

Finalización análoga haciendo abort()

Page 261: 6 Continuacion C++

Modificación de Finalizaciónvoid funcionTerminacion () {

Modificación de Finalizaciónvoid funcionTerminacion () {

cout << "Finalizando" << endl;exit( -1 );

}}void main(int argc, char* argv[]) {

set_terminate(funcionTerminacion);throw "error";throw 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 finalizaría mostrando la

261

ventana de diálogo de error

Page 262: 6 Continuacion C++

ExcepcionesExcepcionesSintaxis de cláusulas “catch”Sintaxis de cláusulas catch

“catch(tipo variable)” o “catch(tipo)”“catch(...)”

I “ h( i bl )”Incorrecto: “catch(... variable)”Si hay más “catch”, el “catch(...)” debe ser el último

Liberación de memoriaAl acceder a parte “catch” se libera la memoria automática, pero el programador debe tener en cuenta la liberación de memoria dinámica

Excepciones posibles en una función“... funcion (...) throw ([tipo]*) {...}”Estas declaraciones se consideran comentarios

En algunas versiones de C++, se producen errores de ejecución al lanzarse excepciones no previstas en la cabecera

262Si en la cabecera no está la declaración “throw”, quiere decir que su código puede lanzar cualquier excepción

Page 263: 6 Continuacion C++

Algunas inconsistencias (*)Algunas inconsistencias ( )

class A {public:

virtual void f () {}virtual void g () throw (int) {}

};class B : public A {private:

virtual void f () {}public:

virtual void g () throw (int, char*) {}}};void main(int argc, char* argv[]) {

B b; A & a=b;// b f() B f i d// b.f(); error, porque B::f es privadoa.f(); // (*) acceso al método privado B::fa.g(); // (*) acceso al método B::g, que puede

// lanzar mas excepciones que A::g

263

// lanzar mas excepciones que A::g}// (*) Inconsistencias eliminadas en Java

Page 264: 6 Continuacion C++

Otros ErroresOtros Errores

M i di á i t dMemoria dinámica agotadaSe lanza una excepción de la clase “bad_alloc”D d d ( l i )Dos modos de respuesta (alternativos)

Atrapar la excepciónModificar la respuesta por defecto (forma análoga aModificar la respuesta por defecto (forma análoga a “set_terminate”)

• set_new_handler(funcionTerminacion);

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

264

Page 265: 6 Continuacion C++

Otros ErroresOtros 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 bytesdelete[] ptr;

}catch( bad alloc &ba) {catch( bad_alloc &ba) {

cout << ba.what( ) << endl;}

}

Page 266: 6 Continuacion C++

Excepciones CFile* pFile = NULL;try {

pFile = new CFile(_T("C:\\WINDOWS\\SYSTEM.INI"),C | C )en MFC CFile::modeRead | CFile::shareDenyNone);

DWORD dwLength = pFile->GetLength();CString str;str.Format(_T("Your SYSTEM.INI file is %u bytes long."),

d L h)Clases CException, CArchiveException, etc

dwLength);AfxMessageBox(str);

}catch(CFileException* pEx) {

E R tE ()Macros TRY y CATCH.

Estas macros sólo f i i

pEx->ReportError();pEx->Delete();

}catch(CMemoryException* pEx) {

// W 't f thi ti 'llfuncionan con excepciones que heredan de CException.

// We can't recover from this memory exception, so we'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().

E D l t ()Evitan tener que borrar un puntero a la excepción (pEx->Delete).

pEx->Delete();AfxAbort();

}

// If ti i th CFil t t// If an exception occurrs in the CFile constructor,// 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) {

266

if (pFile != NULL) {pFile->Close();delete pFile;

}

Page 267: 6 Continuacion C++

Excepciones en MFCCFile* pFile = NULL; Excepciones en MFCCFile pFile = NULL;TRY

{pFile = new CFile( _T( "C:\\WINDOWS\\SYSTEM.INI" ),

CFile::modeRead | CFile::shareDenyNone );CFile::modeRead | CFile::shareDenyNone );ULONGLONG dwLength = pFile->GetLength( );CString str;str.Format( _T( "Your SYSTEM.INI file is %I64u bytes long.") , dwLength );AfxMessageBox( str );AfxMessageBox( str );

}CATCH( CFileException, pEx ){

// Simply show an error message to the user// Simply show an error message to the user.pEx->ReportError();

}AND_CATCH(CMemoryException, pEx){{

AfxAbort( );}END_CATCH// If an exception occurs in the CFile constructor// If an exception occurs in the CFile 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 ) {if ( pFile ! NULL ) {

pFile->Close( );delete pFile;

}

Page 268: 6 Continuacion C++

IndiceIndiceTipos y Declaraciones.p yFunciones.ClasesClases.Espacios de Nombres.Biblioteca Estándar (STL)Biblioteca Estándar (STL).Herencia.M j d EManejo de Errores.Entrada/Salida.

Formato de E/S.Ficheros

268268268

Ficheros.Corrientes de caracteres

268

Page 269: 6 Continuacion C++

Formato de Entrada/SalidaFormato de Entrada/SalidaIndicadores

cout.setf (ios::showpos); // números >=0 con “+”

cout << "Numero:" << 1; // Numero:+1cout << "Numero:" << 2; // Numero:+2cout.unsetf(ios::showpos); cout << "Numero:" << 1; // Numero:+1cout << Numero: << 1; // Numero:+1cout << "Numero:" << 2; // Numero:+2

Manipuladores 1 23 2cout << oct << "Numero1:" << 23 << ",Numero2:"

<< dec << 44;// el 23 en octal y el 44 en decimal// Numero1:27,Numero2:44// u e o , u e o

cout << oct << "Numero:" << 88;// Numero:130

cout << "Numero:" << 88;// N 130

269

// Numero:130

El manipulador “endl” inserta un salto de línea

Page 270: 6 Continuacion C++

Formato de Entrada/Salida

D lt ti i di d i l d

Formato de Entrada/Salida

Dos alternativas: indicadores o manipuladores. Ejemplo de uso equivalente (resultado: “###23”):###23 ):

// Uso 1// Uso 1cout.width(5);

// afecta sólo a la próxima llamada de "<<"cout.fill('#');

// afecta a las próximas llamadas de "<<"cout << 23 << endl;

// Uso 2cout << setw(5) << setfill('#') << 23 << endl;

// necesario “#include <iomanip>”

270

// p// afecta sólo a próxima llamada de “<<“

Page 271: 6 Continuacion C++

Formato de Entrada/Salida

Ot j l ( ú l )

Formato de Entrada/Salida

Otros ejemplos (números reales):cout << 1234.56789 << endl;

// lit l i bl “d bl ”// literales o variables “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;cout << fixed << 1234.56789 << endl; // Resultado:"1234.567890"// Siempre con 6 cifras decimales

271

Page 272: 6 Continuacion C++

Miembros de <iomanip>Miembros de <iomanip>

resetiosflags: Borra los flags que se especifiquen. setbase: Establece la base para enteros. setfill: Establece el carácter que se usará para rellenar espacios en el caso de justificado a la derecha.

ti fl E t bl l fl ifisetiosflags: Establece los flags que se especifiquen.setprecision: Establece la precisión para valores en punto flotantepunto flotante.setw: Establece el ancho.

272

Page 273: 6 Continuacion C++

ios base::fmtflagsios_base::fmtflagsnamespace std { a espace s d {

class ios_base { public: typedef implementation-defined-bitmask-type fmtflags; static const fmtflags boolalpha; t ti t f tfl dstatic const fmtflags dec;

static const fmtflags fixed; static const fmtflags hex; static const fmtflags internal; g ;static const fmtflags left; static const fmtflags oct; static const fmtflags right; t ti t f tfl i tifistatic const fmtflags scientific;

static const fmtflags showbase; static const fmtflags showpoint; static const fmtflags showpos; g p ;static const fmtflags skipws; static const fmtflags unitbuf; static const fmtflags uppercase; static const fmtflags adjustfield;static const fmtflags adjustfield; static const fmtflags basefield; static const fmtflags floatfield; ... }; }

273

Page 274: 6 Continuacion C++

#include "stdafx.h" Formato de Entrada/Salida// output_stream_manip.cpp// compile with: /GR /EHsc#i l d <i t >

o ato de t ada/Sa daManipuladores definidos por el usuario

#include <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++ )for( int i=0; i < l; i++ )(*pos) << ' ';

};}}

_Smanip<int>__cdecl fillblank(int no){{ return (_Smanip<int>(&fb, no));}

int main( ) {cout << "10 blanks follow" << fillblank( 10 ) << ".\n";

}

Page 275: 6 Continuacion C++

Ficheros

L t /E it T t /Bi i

Ficheros

Lectura/Escritura. Texto/Binarios.Distintos modos de apertura. Ejemplo:

(“ l ” i )p.open(“plano.txt”, ios::app); p << “abc”; // añadir datos al // fichero existente

Ficheros binarios Mecanismo de serialización en casos sencillos

Objetos sin atributos punterosP bj i bl d i ió d• Para objetos con variables puntero, se guarda una posición de memoria sin sentido

En Java, la serialización está permitida para 275

p pobjetos

Page 276: 6 Continuacion C++

Ejemplo Ficheros Binariosint x=123456; int y=987654;

Ejemplo Ficheros Binariosint x 123456; int y 987654; cout << "Int:" << sizeof x << endl;

// Int:4// Alternativa: “sizeof (int)”

ofstream f ("datos.bin", ios::binary);f.write((char*) &x, sizeof x); f.write((char*) &y, sizeof x);f.write((char ) &y, sizeof x); f.close();

// Tamaño del fichero “datos.bin”: 8 bytes

x=0; y=0;

ifstream g ("datos.bin", ios::binary);g.read((char*) &x, sizeof x);g.read((char ) &x, sizeof x); g.read((char*) &y, sizeof x); g.close();

276

cout << "X:" << x << endl; cout << "Y:" << y << endl;// X:123456// Y:987654

Page 277: 6 Continuacion C++

Máscaras de aperturaMáscaras de aperturaapp, al fin del stream antes de cada inserción.ate, al fin del stream cuando se crea.binary, para leer un fichero como un stream binario, en vez de un stream de textoun stream de texto.in, para permitir extracción de un stream.out, para permitir inserción de un stream., p ptrunc, 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 );

277

file << "testing"; }

Page 278: 6 Continuacion C++

Corrientes de CaracteresCorrientes de CaracteresLectura/Escritura de corrientes de caracteresLectura/Escritura de corrientes de caracteres

Clase “stringstream” en <sstream>. Alternativa (menos estándar): Clase “strstream” en <strstream>

Útiles en conversiones de tipo (alternativas a “atof”, “atoi”, “itoa”, etc). Ejemplos:

#include <sstream>#include <sstream>using namespace std;// Ejemplo 1string numComoStr1 (double x) {

stringstream f;stringstream f;string s;f << x;f >> s;return s;return s;

}// Ejemplo 2string numComoStr2 (double x) {

ostringstream u;

278

ostringstream u;u << x;return u.str();

}

Page 279: 6 Continuacion C++

Manejo de ErroresManejo de Errores

E i l ió d fi hErrores en manipulación de ficherosAbrir un fichero que no existe, etcPor defecto estas operaciones no lanzan excepciones

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

279

p

Page 280: 6 Continuacion C++

Recursos C++ en la webRecursos C++ en la web

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

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

280