Sobrecarga de Operadores y E/S en C++
Sobrecarga de Operadores y E/S en C++ Sobrecarga de Operadores y E/S en C++
Sobrecarga de Operadores yE/S en C++ Antonio LaTorre de la Fuente
- Page 2 and 3: Índice • Sobrecarga de Funciones
- Page 4 and 5: Sobrecarga de Funciones void print
- Page 6 and 7: Ambigüedad • Se soluciona usando
- Page 9 and 10: Operadores en C++• Lista de opera
- Page 11 and 12: Precedencia de Operadores• Los op
- Page 13 and 14: Sobrecarga de operadores• Ambas n
- Page 15 and 16: Sobrecarga de operadores• Estas d
- Page 17 and 18: Operadores Aritméticos• Suma de
- Page 19 and 20: Operadores de auto-incremento• So
- Page 21 and 22: Funciones “Amigas”class Vector
- Page 23 and 24: Operadores de inserción y extracci
- Page 25 and 26: Operador de Indexación• Es el op
- Page 27 and 28: Constructores de conversión• Hay
- Page 29 and 30: Operadores de conversiónclass Comp
- Page 31 and 32: Operador de llamada a función• E
- Page 33 and 34: Operador new• Al reservar memoria
- Page 35 and 36: Operador delete• Al liberar memor
- Page 37 and 38: Índice • Sobrecarga de Funciones
- Page 39 and 40: Clases istream y ostream• Derivan
- Page 41 and 42: Clases istream y ostream• Manipul
- Page 43 and 44: Clases istream y ostream• Ejemplo
- Page 45 and 46: Clase ostream• La sobrecarga del
- Page 47 and 48: Clase ostream• El método tellp p
- Page 49 and 50: Clase istream• Permite realizar o
- Page 51 and 52: Clase istream• El método get per
<strong>Sobrecarga</strong> <strong>de</strong> <strong>Operadores</strong> yE/S <strong>en</strong> <strong>C++</strong> Antonio LaTorre <strong>de</strong> la Fu<strong>en</strong>te
Índice • <strong>Sobrecarga</strong> <strong>de</strong> Funciones • <strong>Sobrecarga</strong> <strong>de</strong> <strong>Operadores</strong> • Entrada/Salida sobre streams básicos • Entrada/Salida sobre streams <strong>de</strong> fichero • Entrada/Salida sobre streams <strong>de</strong> ca<strong>de</strong>na
<strong>Sobrecarga</strong> <strong>de</strong> Funciones • Nuevo con respecto a C • Funciones con el mismo nombre pero distintoprototipo: número y/o tipo <strong>de</strong> argum<strong>en</strong>tos • Útil si se quiere po<strong>de</strong>r realizar una mismaoperación sobre distintos tipos <strong>de</strong> datos
<strong>Sobrecarga</strong> <strong>de</strong> Funciones void print (double number) {cout
Ambigüedad • ¿Qué pasa si incluimos <strong>en</strong> nuestro código…? unsigned num = 3; print (num); • El compilador no sabe a qué función llamar: func_over.cc:18: error: call of overloa<strong>de</strong>d print(unsigned int&) is ambiguous func_over.cc:6: note: candidates are: void print(int) func_over.cc:7: note:func_over.cc:8: note:void print(int, std::string) void print(double)
Ambigüedad • Se soluciona usando static_cast unsigned num = 3; print (static_cast(num)); • ¿Qué pasaría si hiciéramos…? int num = 3; print (num);
Name Mangling • Estrategia que usa el compilador para po<strong>de</strong>rdifer<strong>en</strong>ciar dos funciones con el mismo nombre int f (void) {return 1;} int f (int) {return 0;} void g (void) {int i = f (), j = f (0);} • Esto se traduciría <strong>en</strong>: int __f_v (void) {return 1;} int __f_i (int) {return 0;} void __g_v (void) {int i = __f_v (), j = __f_i (0);}
<strong>Operadores</strong> <strong>en</strong> <strong>C++</strong>• Lista <strong>de</strong> operadores válidos <strong>en</strong> <strong>C++</strong> + - * / % ^ & |~ ! , = < > =++ -- > == != && ||+= -= *= /= %= ^= &= |== [] () -> ->* new <strong>de</strong>lete• Se <strong>de</strong>claran <strong>de</strong> la sigui<strong>en</strong>te forma: tipo operator operador([argum<strong>en</strong>tos])
<strong>Operadores</strong> <strong>en</strong> <strong>C++</strong>• Hay algunos operadores especiales que nopue<strong>de</strong>n ser sobrecargados • :: (resolución <strong>de</strong> ámbito) • . (selección <strong>de</strong> un miembro) • .* (selección <strong>de</strong> un miembro refer<strong>en</strong>ciado por un puntero) • ?: (operador condicional) • sizeof (tamaño <strong>de</strong>) • typeid (i<strong>de</strong>ntificación <strong>de</strong>l tipo)
Prece<strong>de</strong>ncia <strong>de</strong> <strong>Operadores</strong>• Los operadores <strong>en</strong> <strong>C++</strong> ti<strong>en</strong><strong>en</strong> distintaprece<strong>de</strong>ncia, y a veces no es obvio • Lo mejor es usar () <strong>en</strong> casa <strong>de</strong> no estar seguro • Tabla <strong>de</strong> prece<strong>de</strong>ncias: Inglés: http://www.cplusplus.com/doc/tutorial/operators/ Español: http://es.wikipedia.org/wiki/<strong>Operadores</strong>_<strong>en</strong>_C_y_C%2B%2B
<strong>Sobrecarga</strong> <strong>de</strong> operadores• Po<strong>de</strong>mos sobrecargar tanto operadores unarioscomo binarios tipo_ret operator op_unario (tipo1 arg1); tipo_ret operator op_binario (tipo1 arg1, tipo2 arg2); • En este caso, ambos argum<strong>en</strong>tos se muestran <strong>de</strong>manera explícita
<strong>Sobrecarga</strong> <strong>de</strong> operadores• Ambas notaciones son equival<strong>en</strong>tes C operator- (C n) {…} C operator- (C n, C m) {…} int main (void) { } C a, b, c, d;c = -b;d = b – a; int main (void) { } C a, b, c, d;c = operator- (b);d = operator- (b, a);
<strong>Sobrecarga</strong> <strong>de</strong> operadores• Si los operadores son métodos <strong>de</strong> una clase, uno<strong>de</strong> los argum<strong>en</strong>tos es implícito (aquél que invocaal operador) class C { } public: C operator- ();C operator- (C);
<strong>Sobrecarga</strong> <strong>de</strong> operadores• Estas dos notaciones son equival<strong>en</strong>tes int main (void) { C a, b, c, d; c = -b; d = b – a; } int main (void) { C a, b, c, d; c = b.operator-(); d = b.operator-(a); }
<strong>Sobrecarga</strong> <strong>de</strong> operadores• Ejemplo: Números Complejos class Complejo { } public:Complejo (double r, double i) : real(r), imag(i) {}… private:double real;double imag;
<strong>Operadores</strong> Aritméticos• Suma <strong>de</strong> números complejos: Complejo Complejo::operator+ (const Complejo& z2) const { } Complejo res (0, 0); res.real = this->real + z2.real;res.img = this->img + z2.img; return res;
<strong>Operadores</strong> Relacionales• Comparación <strong>de</strong> números complejos: bool Complejo::operator== (const Complejo& z2) const { } return this->real == z2.real && this->imag == z2.imag;
<strong>Operadores</strong> <strong>de</strong> auto-increm<strong>en</strong>to• Son operadores unarios • Permit<strong>en</strong> pre-increm<strong>en</strong>tar y post-increm<strong>en</strong>tar elvalor <strong>de</strong> una variable Pre-increm<strong>en</strong>to:C C::operator++() Post-increm<strong>en</strong>to: C C::operator++(int x) Complejo Complejo::operator++() { } real += 1;return *this;
Funciones “Amigas”• Son funciones aj<strong>en</strong>as a una clase que pue<strong>de</strong>nacce<strong>de</strong>r a los elem<strong>en</strong>tos privados <strong>de</strong> esa clase • Ejemplo: • T<strong>en</strong>emos dos clases: Vector y Matriz • Queremos <strong>de</strong>finir el producto vectorial <strong>en</strong>treambas clases • El cont<strong>en</strong>ido <strong>de</strong> los objetos es privado
Funciones “Amigas”class Vector { fri<strong>en</strong>d operator* (const Matriz&matriz, const Vector& vector); } public: … private:int size;int* data; class Matriz { fri<strong>en</strong>d operator* (const Matriz&matriz, const Vector& vector); } public: … private:int rows, columns;int** data; Vector operator* (const Matriz& matriz, const Vector& vector) {…}
<strong>Operadores</strong> <strong>de</strong> asignación• Se sobrecargan para evitar la copia binaria <strong>de</strong>objetos class Vector { } public:Vector& operator= (const Vector& vector) {size = vector.size;data = new int[vector.size];for (unsigned i = 0; i < size; i++)data[i] = vector.data[i];return *this;} private:int size;int* data; class Vector { } public:Vector& operator= (const Vector&vector) {size = vector.size;data = vector.data;return *this;} private:int size;int* data;
<strong>Operadores</strong> <strong>de</strong> inserción y extracción• Permit<strong>en</strong> escribir / leer <strong>en</strong> la salida / <strong>en</strong>tradaestándar • Hay que sobrecargar los operadores: ostream& operator> (istream& is, T& arg) • Po<strong>de</strong>mos hacer que estos métodos sean amigos<strong>de</strong> nuestra clase o implem<strong>en</strong>tar un métodopúblico que imprima los datos
<strong>Operadores</strong> <strong>de</strong> inserción y extracciónclass Complejo { } public:void printComplejo(ostream & os);… private:double real;double imag; ostream& operator
Operador <strong>de</strong> In<strong>de</strong>xación• Es el operador [] • Es un operador binario y <strong>de</strong> clase: recibe elobjeto don<strong>de</strong> se aplica y el índice facilitado • Útil, p.ej., para acceso seguro a datos: int Vector::operator[] (int i) { } if (i >= 0 && i < this->size)return data[i];else {cout
Conversión <strong>de</strong> tipos• Hay dos posibilida<strong>de</strong>s para llevar a caboconversiones <strong>en</strong>tre tipos <strong>de</strong>finidos por elusuario: • Los constructores <strong>de</strong> conversión • Los operadores <strong>de</strong> conversión • Son útiles para hacer, por ejemplo: Complejo a (2, 3), b (0, 0); b = a + 5;
Constructores <strong>de</strong> conversión• Hay que añadir un constructor que nos permitacrear el objeto a partir <strong>de</strong> un objeto <strong>de</strong>l tipo quequeramos convertir class Complejo { }public:Complejo (double r, double i) : real(r), imag(i) {}Complejo (int r) : real(r), imag(0) {}Complejo operator+ (const Complejo& z2) const;… private:double real, imag; Complejo a (2, 3), b (0, 0); b = a + 5;
<strong>Operadores</strong> <strong>de</strong> conversión• Se usan para proporcionar una conversión <strong>de</strong> untipo <strong>de</strong> usuario a otro tipo (<strong>de</strong> usuario o no) • Ti<strong>en</strong>e la sintaxis: C::operator T(); • Don<strong>de</strong> C es el tipo <strong>de</strong> usuario que queremosconvertir y T es el tipo <strong>en</strong> el que queremosconvertir C
<strong>Operadores</strong> <strong>de</strong> conversiónclass Complejo { } public:Complejo (double r, double i) : real(r), imag(i) {}operator double() {return real;}Complejo operator+ (const Complejo& z2) const;… private:double real, imag; Complejo a (2, 3); double b = a + 5; double c = a.operator double() + 5; double d = static_cast(a) + 5;
Ambigüeda<strong>de</strong>s <strong>en</strong> la conversiónSurg<strong>en</strong> si hay varias conversiones implícitas posibles class Complejo { }public:Complejo (double r = 0, double i = 0): real(r), imag(i) {}operator double() {return real;}Complejo operator+ (const Complejo& z2) const;… private:double real, imag; Complejo a(2, 3), c(0,0); double b = 5; c = a + b; El compilador no sabe siconvertir “b” a“Complejo” y realizarla suma o convertir“a” a “double”, hacerla suma y convertir elresultado a Complejo.
Operador <strong>de</strong> llamada a función• Es el operador () • Siempre <strong>de</strong>be ser <strong>de</strong>finido <strong>de</strong>ntro <strong>de</strong> una clase • x (y, z) se interpreta como x.operator (y, z) • Útil para implem<strong>en</strong>tar callbacks (pasar códigocomo argum<strong>en</strong>to <strong>de</strong> una función). Los<strong>de</strong>nominados Objetos Función • También para el acceso a matricesmultidim<strong>en</strong>sionales
Operador <strong>de</strong> llamada a funciónclass Inicializar {private:double val;public:Inicializar (double x = 0) : val(x) {}void operator() (Vector& v); }; void Inicializar::operator() (Vector& v) { for (unsigned i = 0; i < vector.size(); i++) v[i] = this->val; } int main (void) { Vector v(5); Inicializar ini(1); ini(v); }
Operador new• Al reservar memoria con new y new[] se invoca a lasfunciones operator new y operator new[]: void* operator new (size_t tamaño); void* operator new[] (size_t tamaño); • Estas funciones reservan y memoria y luego llaman elconstructor correspondi<strong>en</strong>te • Se pue<strong>de</strong>n sobrecargar para una clase C: void* C::operator new (size_t tamaño); void* C::operator new[] (size_t tamaño); • Son funciones estáticas aunque no se <strong>de</strong>clar<strong>en</strong> como tal(static), porque se invocan antes que el constructor • Primero se busca <strong>en</strong> la clase (y clases base) y luego la global
Operador newvoid* Vector::operator new (size_t tam) { reservarMemoria (tam, 0); } void* Vector::operator new[] (size_t tam) { reservarMemoria (tam, 0); } void* Vector::reservarMemoria (size_t tam, char c) { void* p = malloc (tam); if (p == 0) { cout
Operador <strong>de</strong>lete• Al liberar memoria con <strong>de</strong>lete y <strong>de</strong>lete[] se invoca a lasfunciones operator <strong>de</strong>lete y operator <strong>de</strong>lete[]: void operator <strong>de</strong>lete (void*); void operator <strong>de</strong>lete[] (void*); • Estas funciones llaman al <strong>de</strong>structor y luego liberan la memoria<strong>de</strong>l objeto • Se pue<strong>de</strong> sobrecargar para una clase C: void C::operator <strong>de</strong>lete (void*, [size_t]); void C::operator <strong>de</strong>lete[] (void*, [size_t]); • Son funciones estáticas aunque no se <strong>de</strong>clar<strong>en</strong> como tal(static), porque se invocan <strong>de</strong>spués <strong>de</strong>l <strong>de</strong>structor • Primero se busca <strong>en</strong> la clase (y clases base) y luego la global
Operador <strong>de</strong>letevoid Vector::operator <strong>de</strong>lete (void* p, size_t tam) { if (p) memset (p, 0, tam); free (p); } void Vector::operator <strong>de</strong>lete[] (void* p, size_t tam) { if (p) memset (p, 0, tam); free (p); }
Índice • <strong>Sobrecarga</strong> <strong>de</strong> Funciones • <strong>Sobrecarga</strong> <strong>de</strong> <strong>Operadores</strong> • Entrada/Salida sobre streams básicos • Entrada/Salida sobre streams <strong>de</strong> fichero • Entrada/Salida sobre streams <strong>de</strong> ca<strong>de</strong>na
Visión G<strong>en</strong>eral <strong>de</strong> la E/S <strong>en</strong> <strong>C++</strong>• Streams y Buffers • Especializaciones según el tipo <strong>de</strong> operación y elorig<strong>en</strong>/<strong>de</strong>stino <strong>de</strong> los datos
Clases istream y ostream• Derivan <strong>de</strong> la clase ios • Deb<strong>en</strong> ser conectadas a un buffer (<strong>de</strong>l tipo quesea) • cin y cout son <strong>de</strong> tipo istream y ostream • Normalm<strong>en</strong>te, para hacer E/S sobre ficheros oca<strong>de</strong>nas se usan las clases especializadas, pero sepodrían usar estas clases básicas • Para usarlas: #inclu<strong>de</strong>
Clases istream y ostream• Los Manipuladores nos permit<strong>en</strong> cambiar lasopciones <strong>de</strong> formato <strong>de</strong> los streams (#inclu<strong>de</strong>) • Son funciones especialm<strong>en</strong>te diseñadas paratrabajar junto con los operadores <strong>de</strong> inserción() • Se modifica el formato <strong>en</strong>ca<strong>de</strong>nándolos al objetoque repres<strong>en</strong>ta el stream cout
Clases istream y ostream• Manipuladores sin parámetros:(no)boolapha: Mostrar booleanos como true y false(no)showbase: Mostrar prefijo <strong>de</strong> tipo (0x, 0, etc.)(no)showpoint: Forzar la escritura <strong>de</strong>l punto <strong>de</strong>cimal(no)showpos: Forzar la escritura <strong>de</strong> un ‘+’ para valores positivos(no)skipws: Permite ignorar caracteres <strong>de</strong> espaciado(no)unitbuf: Forzar el vaciado <strong>de</strong>l buffer tras cada operación(no)uppercase: Mostrar caracteres alfabéticos <strong>en</strong> mayúsculas<strong>de</strong>c, hex, oct: Cambiar base (<strong>de</strong>cimal, hexa<strong>de</strong>cimal y octal)fixed, sci<strong>en</strong>tific: Usar notación <strong>de</strong> coma fija o ci<strong>en</strong>tíficainternal, left, right: Alinear el texto<strong>en</strong>dl, <strong>en</strong>ds, flush: Finalizar línea, ca<strong>de</strong>na y vaciar buffer
Clases istream y ostream• Manipuladores con parámetrossetprecision (int): Fija la precisión <strong>en</strong> coma flotantesetw (int): Fija el tamaño <strong>de</strong> un campo (que se rell<strong>en</strong>aautomáticam<strong>en</strong>te <strong>en</strong> caso <strong>de</strong> ser necesario)setfill (char): Selecciona el carácter para el rell<strong>en</strong>osetbase (int): Fija la base numérica a usar (8, 10 ó 16)setiosflags (mask): Fija cualquiera <strong>de</strong> los anteriores flagsresetiosflags (mask): Reinicia los flags a los valores por <strong>de</strong>fecto• Otra forma <strong>de</strong> hacer lo mismo • Manipuladores sin parámetros: métodos setf y unsetf • Manipuladores con parámetros: métodos propios (fill, width,precision, etc.)
Clases istream y ostream• Ejemplos cout
Clase ostream• Permite hacer operaciones <strong>de</strong> escritura con y sinformato • Sin formato: put y write • Con formato: operator
Clase ostream• La sobrecarga <strong>de</strong>l operador <strong>de</strong> inserción permiterealizar escritura con formato • Se pue<strong>de</strong> sobrecargar para cualquier tipo ostream& operator
Clase ostream• El método put permite escribir un carácter <strong>en</strong> elstream ostream& put (char ch) • El método write permite escribir n caracteres <strong>de</strong>un array <strong>en</strong> el stream ostream& write (const char* pch, int n) • El método flush fuerza el vaciado <strong>de</strong>l bufferasociado al stream ostream& flush ()
Clase ostream• El método tellp permite obt<strong>en</strong>er la posición <strong>en</strong>el stream <strong>de</strong> salida (principalm<strong>en</strong>te ficheros) pos_type tellp () • Los métodos seekp permit<strong>en</strong> cambiar la posición<strong>de</strong> escritura <strong>en</strong> relación a la posición actual… ostream& seekp (pos_type pos) • …o <strong>en</strong> relación a una posición <strong>de</strong> refer<strong>en</strong>cia ostream& seekp (off_type <strong>de</strong>s, ios_base::seekdir pos)
Clase ostream• Ejemplos: const char* ca<strong>de</strong>na = “Hola mundo”; cout
Clase istream• Permite realizar operaciones <strong>de</strong> lectura con y sinformato: • Sin formato: get, getline, read, ignore, peek,gcount, unget, putback • Con formato: operator>> • Al igual que la clase ostream, permite gestionarerrores y reposicionar el puntero <strong>de</strong> lectura
Clase istream• La sobrecarga <strong>de</strong>l operador <strong>de</strong> extracciónpermite realizar lectura con formato • Se pue<strong>de</strong> sobrecargar para cualquier tipo istream& operator>> (istream& is, T& data) • Y usar los manipuladores vistos anteriorm<strong>en</strong>te(aunque algunos pue<strong>de</strong>n t<strong>en</strong>er s<strong>en</strong>tidoúnicam<strong>en</strong>te para la clase ostream)
Clase istream• El método get permite leer un carácter <strong>de</strong>lstream: istream& get (char& ch) • El método getline permite leer una línea, con unalongitud máxima hasta <strong>en</strong>contrar un <strong>de</strong>limitador istream& getline (char* ch, int n, char <strong>de</strong>lim = “\n”) • El método read permite leer n caracteres istream& read (char* ch, int n)
Clase istream• El método ignore extrae y <strong>de</strong>scarta una ca<strong>de</strong>na<strong>de</strong> hasta n caracteres, mi<strong>en</strong>tras no <strong>en</strong>cu<strong>en</strong>tre un<strong>de</strong>limitador dado istream& ignore (int n = 1, int <strong>de</strong>lim = eof ()) • El método peek <strong>de</strong>vuelve el sigui<strong>en</strong>te carácter<strong>de</strong>l stream sin extraerlo int peek () const
Clase istream• El método gcount <strong>de</strong>vuelve el número <strong>de</strong>caracteres leídos <strong>en</strong> la última extracción sinformato int gcount () const • El método unget <strong>de</strong>vuelve el último carácterextraído al stream istream& unget () • El método putback <strong>de</strong>vuelve c al stream istream& putback (char c)
Clase istream• El método tellg permite obt<strong>en</strong>er la posición <strong>en</strong> elstream <strong>de</strong> <strong>en</strong>trada (principalm<strong>en</strong>te ficheros) pos_type tellg () • Los métodos seekg permit<strong>en</strong> cambiar la posición<strong>de</strong> lectura <strong>en</strong> relación a la posición actual… istream& seekg (pos_type pos) • …o <strong>en</strong> relación a una posición <strong>de</strong> refer<strong>en</strong>cia istream& seekg (off_type <strong>de</strong>s, ios_base::seekdir pos)
Clase istream• Ejemplos char c, cad [100], cad2[10]; cin >> cad;// Introducimos por teclado Hola mundo cin.get(c);// cad = Hola, c= cin.getline (cad, 100, \n); // cad=mundo cin.read (cad2, 10); // Introducimos por teclado // Hola mundo cruel.Adios cout cad; // cad=!Adios!
Clase iostream• Clase <strong>de</strong>rivada tanto <strong>de</strong> istream como <strong>de</strong> ostream • Proporciona acceso <strong>de</strong> lectura/escritura astreams • Pres<strong>en</strong>ta los mismos métodos que las clases <strong>de</strong>las que <strong>de</strong>riva
Gestión <strong>de</strong> errores• Los streams manejan 4 bits <strong>de</strong> error: • eofbit: Se alcanzó el final <strong>de</strong>l fichero <strong>en</strong> una operación <strong>de</strong> E/S • failbit: El método <strong>de</strong> E/S falló • badbit: Hubo un problema con el stream al realizar laoperación • goodbit: Ninguno <strong>de</strong> los anteriores bits está activado • Los métodos eof, fail, bad y good <strong>de</strong>vuelv<strong>en</strong> elvalor <strong>de</strong> estos bits
Índice • <strong>Sobrecarga</strong> <strong>de</strong> Funciones • <strong>Sobrecarga</strong> <strong>de</strong> <strong>Operadores</strong> • Entrada/Salida sobre streams básicos • Entrada/Salida sobre streams <strong>de</strong>fichero • Entrada/Salida sobre streams <strong>de</strong> ca<strong>de</strong>na
E/S sobre streams <strong>de</strong> fichero• Proporcionada por el fichero <strong>de</strong> cabecera:#inclu<strong>de</strong> • Provee <strong>de</strong> las clases ofstream (salida), ifstream(<strong>en</strong>trada) y fstream (<strong>en</strong>trada/salida) • Distintos modos para abrir un fichero: ios::in, ios::out, ios::trunc, ios::app, ios::binary, ios::ate • El fichero se pue<strong>de</strong> abrir <strong>en</strong> el constructor o conel método op<strong>en</strong>
Métodos <strong>de</strong> apoyo• El método eof indica si se alcanzó el final <strong>de</strong>lfichero: bool eof () const • El método is_op<strong>en</strong> indica si existe un ficheroabierto asociado con el stream bool is_op<strong>en</strong> () const • El método close cierra el fichero abierto y lo<strong>de</strong>sliga <strong>de</strong>l stream bool close ()
Clase ofstream• Clase <strong>de</strong>rivada <strong>de</strong> ostream especializada <strong>en</strong>realizar escrituras sobre ficheros • El fichero se pue<strong>de</strong> abrir al construir un objeto<strong>de</strong> tipo ofstream o con el método op<strong>en</strong> ofstream (const char* nombre_fichero,ios_base::op<strong>en</strong>mo<strong>de</strong> modo = ios::out | ios::trunc) void op<strong>en</strong> (const char* nombre_fichero,ios_base::op<strong>en</strong>mo<strong>de</strong> modo = ios::out | ios::trunc)
Clase ofstream• Ejemplo: ofstream of (fichero.txt"); of.write ("Hola mundo\n", 11); of
Clase ifstream• Clase <strong>de</strong>rivada <strong>de</strong> istream especializada <strong>en</strong>realizar lecturas <strong>de</strong>s<strong>de</strong> ficheros • El fichero se pue<strong>de</strong> abrir al construir un objeto<strong>de</strong> tipo ifstream o con el método op<strong>en</strong> ifstream (const char* nombre_fichero,ios_base::op<strong>en</strong>mo<strong>de</strong> modo = ios::in) void op<strong>en</strong> (const char* nombre_fichero,ios_base::op<strong>en</strong>mo<strong>de</strong> modo = ios::in)
Clase ifstream• Ejemplo: ifstream f (fichero.txt"); char buffer[100]; f.getline (buffer, 100); cout
Clase fstream• Combina las funcionalida<strong>de</strong>s <strong>de</strong> ifstream yofstream • El fichero se pue<strong>de</strong> abrir al construir un objeto<strong>de</strong> tipo fstream o con el método op<strong>en</strong> fstream (const char* nombre_fichero,ios_base::op<strong>en</strong>mo<strong>de</strong> modo = ios::in | ios::out) void op<strong>en</strong> (const char* nombre_fichero,ios_base::op<strong>en</strong>mo<strong>de</strong> modo = ios::in | ios::out)
E/S usando Registros• Po<strong>de</strong>mos escribir estructuras <strong>de</strong> datos complejas• Los datos se guardan <strong>en</strong> formato binario, <strong>en</strong>lugar <strong>de</strong> escribirse carácter a carácter • Po<strong>de</strong>mos hacerlo con los métodos read y write • Requiere una conversión <strong>de</strong> la estructura <strong>en</strong> unarray <strong>de</strong> caracteres • Uso <strong>de</strong> reinterpret_cast()
E/S usando Registrosstruct nodo_ag<strong>en</strong>da {char nombre[30];char direccion[40];long telefono; }; nodo_ag<strong>en</strong>da persona; cin.getline (30, persona.nombre); cin.getline (40, persona.direccion); cin >> persona.telefono; ofstream ofs (“ag<strong>en</strong>da”); ofs.write (reinterpret_cast(&persona), sizeof(nodo_ag<strong>en</strong>da)); ofs.close ();
Índice • <strong>Sobrecarga</strong> <strong>de</strong> Funciones • <strong>Sobrecarga</strong> <strong>de</strong> <strong>Operadores</strong> • Entrada/Salida sobre streams básicos • Entrada/Salida sobre streams <strong>de</strong> fichero • Entrada/Salida sobre streams <strong>de</strong>ca<strong>de</strong>na
La clase String• Clase que sirve para trabajar con ca<strong>de</strong>nas <strong>de</strong>caracteres • También almac<strong>en</strong>a el tamaño <strong>de</strong> la ca<strong>de</strong>na • Gestiona automáticam<strong>en</strong>te la memoria dinámicaasociada a la ca<strong>de</strong>na • Facilita las operaciones más habituales conca<strong>de</strong>nas <strong>de</strong> caracteres • Hace falta incluir el sigui<strong>en</strong>te fichero <strong>de</strong>cabecera: #inclu<strong>de</strong>
La clase String• Cómo construimos un objeto <strong>de</strong> tipo string: string cad1; // Construye una ca<strong>de</strong>na vacía string cad2 (cad1); // Constructor <strong>de</strong> copia char arr[] = “Hola mundo”); string cad3 (arr); // Constructor a partir <strong>de</strong> un array <strong>de</strong> char • Po<strong>de</strong>mos consultar el tamaño <strong>de</strong> una ca<strong>de</strong>na: cout
La clase String• Po<strong>de</strong>mos asignar ca<strong>de</strong>nas sin miedo (la memoriala gestiona la propia clase): string cad1 = “Hola mundo”; string cad2 = “Adios mundo”; cad2 = cad1; • Si nos interesa, po<strong>de</strong>mos recuperar el array <strong>de</strong>caracteres asociado al objeto string string cad1 = “abc<strong>de</strong>fgh”; const char* arr1 = cad1.c_str(); // Sí aña<strong>de</strong> ‘\0’ const char* arr2 = cad1.data(); // No aña<strong>de</strong> ‘\0’ char buffer[80]; cad1.copy (buffer, cad1.size(), 0);
La clase String• También po<strong>de</strong>mos realizar las operaciones <strong>de</strong>comparación habituales: ==, !=, , = • Se comparan letra por letra y se usa el or<strong>de</strong>nalfabético string str1 = “abc<strong>de</strong>fg”, str2 = “Abc<strong>de</strong>fg”; if (str1 < str2) cout
La clase String• Se pue<strong>de</strong>n insertar caracteres <strong>en</strong> una ca<strong>de</strong>na: string cad = “Hola”; cad += “ mundo”; // Aña<strong>de</strong> “ mundo” al final cad.app<strong>en</strong>d (“ cruel”); // Aña<strong>de</strong> “ cruel” al final cad.insert (11, “nada “); // Inserta “nada “ <strong>en</strong> la posición 11 cout
La clase String• También po<strong>de</strong>mos buscar subca<strong>de</strong>nas: int pos; string cad = “abc<strong>de</strong>fghijk”; pos = cad.find (“efg”); // pos = 4 pos = cad.find (“i”); // pos = 8 • Reemplazar subca<strong>de</strong>nas: cad.replace (cad.find (“efg”), 2, “ zyx ”); // cad = “abcd zyx ghijk” • Y extraer subca<strong>de</strong>nas: string cad1 = “Esto es una ca<strong>de</strong>na”; string cad2 = cad1.substr (12, 6); // cad2 = “ca<strong>de</strong>na”
Entrada/Salida sobre streams <strong>de</strong> ca<strong>de</strong>na• Proporcionada por el fichero <strong>de</strong> cabecera:#inclu<strong>de</strong> • Provee <strong>de</strong> las clases ostringstream (salida),istringstream (<strong>en</strong>trada) y stringstream (e/s) • Permite realizar operaciones <strong>de</strong> E/S sobreobjetos <strong>de</strong> tipo string (parecido al sprintf <strong>de</strong> C) • Se pue<strong>de</strong>n usar los métodos <strong>de</strong> las clases básicasistream, ostream y stream (respectivam<strong>en</strong>te)
Entrada/Salida sobre streams <strong>de</strong> ca<strong>de</strong>na• Defin<strong>en</strong> dos métodos adicionales: string str ( ) constvoid str (const string & s) • Permit<strong>en</strong> recuperar e inicializar la ca<strong>de</strong>naasociada al stream • También se les pue<strong>de</strong> asociar una ca<strong>de</strong>na <strong>en</strong> elconstructor istringstream (const string& str,ios_base::op<strong>en</strong>mo<strong>de</strong> modo = ios_base::in)
Ejemplo con ostringstreamostringstream buffer; string nombre = "Antonio"; int edad = 27; char aficion[] = "leer"; buffer
Ejemplo con istringstreamstring nombre2; int edad2 = 0; char aficion2[80]; istringstream buffer2 ("Antonio , 27 , leer"); buffer2 >> nombre2; // nombre2 = Antonio buffer2.ignore(100, ','); // Descartamos la , buffer2 >> edad2; // edad2 = 27 buffer2.ignore(100, ','); // Descartamos la , buffer2 >> aficion2; // aficion2 = leer