c++ (avanzado)
TRANSCRIPT
C++ Avanzado
Tema 5
TACC II111
TACC IICurso 2008/091
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
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
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
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
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};
Á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
Á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
Á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
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
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
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
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
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
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
OperadoresOperadoresPrioridad (decreciente)
16161616
OperadoresOperadoresPrioridad (decreciente)
17171717
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
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
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
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
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
ConstantesConstantes
Punteros:Puntero constante:
l * (“ ” i t “* ” k)long * const p = № (“p=…” incorrecto, “*p=…” ok) Puntero a constante:
const long * p = № (“*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
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)
IndiceIndiceTipos y Declaraciones.p yFunciones.ClClases.Espacios de Nombres.pBiblioteca Estándar (STL).HerenciaHerencia.Manejo de Errores.Entrada/Salida.
25252525
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
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{ …}
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
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;
}
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);
}
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);
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
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
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;
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
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”
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 )
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
}
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;
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
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
)
#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
#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
#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); }
#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); }
#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); }
#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); }
#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); }
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
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
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
( );}
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
( );}
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
( );}
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 “=“
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
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
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
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
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 &'
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
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); }
#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;
}
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
#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 &'
#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);
}
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.
#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);
}
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
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”
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
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}
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.
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.
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.
#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
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).
#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);}
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
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;
}
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();
}
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.
};
#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() { }
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
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 ‘::’
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.
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
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;
}
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();. . .
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
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
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
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.
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
}
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 );}
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
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
…
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
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
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 {…};
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
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; }
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
*/
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
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
}
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
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;
}
TemplatesTemplates
Typenameclass Z{public:
class U{};};
template <class B>class A{
typename B::U x;}};
void main(){
107
{A<Z> a;
}
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}
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
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
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
ContenedoresOperaciones y Eficiencia
112112112
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++] << " ");
}
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}
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); }
};
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.
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.
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.
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&)
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;
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
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 &)"
}
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
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
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
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
}
#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';
}
#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!";
}
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
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
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.
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();
}
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);
}
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
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;}
};
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();
}
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;
}};
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
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);
}
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);
}
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;
}
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";
}
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++);}
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 () () )}
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;
}
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 ;
}
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()));}
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();
}}
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";
}
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++] << " " );}
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"));
}
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
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
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);?
}
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
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";}
};
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
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
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
}
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.
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*.
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
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};
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
};
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
}};
}
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
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
}
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
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()}
};
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";}}};
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
}
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?
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
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;}
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;}
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
}
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
}
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);
}
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);
}
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;
}
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
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(); }
#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
}
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
}
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
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;}
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
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)
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";
}}
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(); }
};
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";
}
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;
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; }
};
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;
}
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
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) {}
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);
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);
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
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
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
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
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.
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
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
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
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;
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”
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
#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
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();}
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
}
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
}
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())
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;
};
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();
// ...
};
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
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 }
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
}
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
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
}
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
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&);
};
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;
}
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);
}
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]}
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();
}
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 ->.
#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";
}
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);
}
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!!
}
#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
...
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
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]
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
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&);
};
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);}
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;
}
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';
}
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
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
; //}
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
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*
}
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()
};
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;
}
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}
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');
}
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.
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();//...
};
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”)
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
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
}
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
}
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
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
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”
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()
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
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
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()
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
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
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
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
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;}
}
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;
}
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;
}
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
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
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 “<<“
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
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
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
#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";
}
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
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
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"; }
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();
}
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
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