Está en la página 1de 78

Sobrecarga de Operadores y E/S en C++

Antonio LaTorre de la Fuente


ndice

Sobrecarga de Funciones
Sobrecarga de Operadores
Entrada/Salida sobre streams bsicos
Entrada/Salida sobre streams de chero
Entrada/Salida sobre streams de cadena

Sobrecarga de Funciones

Nuevo con respecto a C
Funciones con el mismo nombre pero distinto til si se quiere poder realizar una misma
operacin sobre distintos tipos de datos
prototipo: nmero y/o tipo de argumentos

Sobrecarga de Funciones

void print (double number) {cout << number << endl;}

void print (int number) {cout << number << endl;}

void print (int number, string s = hola) {

cout << number << , << s << endl;
}

Ambigedad

Qu pasa si incluimos en nuestro cdigo?

unsigned num = 3;
print (num);

El compilador no sabe a qu funcin llamar:



func_over.cc:18: error: call of overloaded 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)

Ambigedad

Se soluciona usando static_cast

unsigned num = 3;
print (static_cast<double>(num));
int num = 3;
print (num);

Qu pasara si hiciramos?

Name Mangling

Estrategia que usa el compilador para poder
int f (void) {return 1;}
int f (int) {return 0;}

diferenciar dos funciones con el mismo nombre


Esto se traducira en:



int __f_v (void) {return 1;}
int __f_i (int) {return 0;}

void g (void) {int i = f (), j = f (0);}


void __g_v (void) {int i = __f_v (), j = __f_i (0);}



ndice

Sobrecarga de Funciones
Sobrecarga de Operadores
Entrada/Salida sobre streams bsicos
Entrada/Salida sobre streams de chero
Entrada/Salida sobre streams de cadena

Operadores en C++

Lista de operadores vlidos en C++

+ ~ ++ += <<= ! --= >>= * , << *= [] / = >> /= () % < == %= -> ^ > != ^= ->* & <= && &= new | >= || |= delete

Se declaran de la siguiente forma:



tipo operator operador([argumentos])

Operadores en C++

Hay algunos operadores especiales que no
pueden ser sobrecargados

:: (resolucin de mbito)
. (seleccin de un miembro)
.* (seleccin de un miembro referenciado por un puntero)
?: (operador condicional)
sizeof (tamao de)
typeid (identicacin del tipo)

Precedencia de Operadores

Los operadores en C++ tienen distinta Lo mejor es usar () en casa de no estar seguro
Tabla de precedencias:

Ingls: http://www.cplusplus.com/doc/tutorial/operators/
Espaol: http://es.wikipedia.org/wiki/Operadores_en_C_y_C%2B%2B


precedencia, y a veces no es obvio


Sobrecarga de operadores

Podemos sobrecargar tanto operadores unarios
como binarios

tipo_ret operator op_unario (tipo1 arg1);
tipo_ret operator op_binario (tipo1 arg1, tipo2 arg2);

En este caso, ambos argumentos se muestran de


manera explcita

Sobrecarga de operadores

Ambas notaciones son equivalentes




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

Sobrecarga de operadores

Si los operadores son mtodos de una clase, uno
de los argumentos es implcito (aqul que invoca al operador)

class C {
public:

C operator- (); C operator- (C);
}


Sobrecarga de operadores

Estas dos notaciones son
equivalentes


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

Sobrecarga de operadores

Ejemplo: Nmeros Complejos


class Complejo {
public: Complejo (double r, double i) : real(r), imag(i) {}
private: double real; double imag;
}

Operadores Aritmticos

Suma de nmeros 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;
}

Operadores Relacionales

Comparacin de nmeros complejos:


bool Complejo::operator== (const Complejo& z2) const {

return this->real == z2.real && this->imag == z2.imag;
}

Operadores de auto-incremento

Son operadores unarios


Permiten pre-incrementar y post-incrementar el
valor de una variable

Pre-incremento:
C C::operator++()
Post-incremento:
C C::operator++(int x)

Complejo Complejo::operator++() {

real += 1; return *this;
}

Funciones Amigas

Son funciones ajenas a una clase que pueden Ejemplo:
Tenemos dos clases: Vector y Matriz
Queremos denir el producto vectorial entre El contenido de los objetos es privado

ambas clases
acceder a los elementos privados de esa clase

Funciones Amigas

class Vector {
friend operator* (const Matriz& matriz, const Vector& vector);
public:


private: int size; int* data;
}
class Matriz {
friend operator* (const Matriz& matriz, const Vector& vector);
public:


private: int rows, columns; int** data;
}

Vector operator* (const Matriz& matriz, const Vector& vector) {}


Operadores de asignacin

Se sobrecargan para evitar la copia binaria de
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;

Operadores de insercin y extraccin


Permiten escribir / leer en la salida / entrada Hay que sobrecargar los operadores:

ostream& operator<< (ostream& os, const T& arg)
istream& operator>> (istream& is, T& arg)

estndar

Podemos hacer que estos mtodos sean amigos


de nuestra clase o implementar un mtodo pblico que imprima los datos


Operadores de insercin y extraccin



class Complejo {
public:
void printComplejo(ostream & os);
private: double real; double imag;
}
ostream& operator<< (ostream& os, const Complejo& c) {

c.printComplejo(os); return os;
}

class Complejo {
public: friend ostream& operator<< (ostream& os, const Complejo& c);
private: double real; double imag;
}
ostream& operator<< (ostream& os, const Complejo& c) {

os << c.real <<
}

Operador de Indexacin

Es el operador []
Es un operador binario y de clase: recibe el til, p.ej., para acceso seguro a datos:

int Vector::operator[] (int i) {

if (i >= 0 && i < this->size)

return data[i]; else {

cout << Posicin incorrecta: << i << endl;

return 0; }
}

objeto donde se aplica y el ndice facilitado


Conversin de tipos

Hay dos posibilidades para llevar a cabo Los constructores de conversin
Los operadores de conversin
Son tiles para hacer, por ejemplo:






Complejo a (2, 3), b (0, 0);

b = a + 5;

conversiones entre tipos denidos por el usuario:


Constructores de conversin

Hay que aadir un constructor que nos permita
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;

crear el objeto a partir de un objeto del tipo que queramos convertir


Operadores de conversin

Se usan para proporcionar una conversin de un Tiene la sintaxis:


tipo de usuario a otro tipo (de usuario o no)

C::operator T();

Donde C es el tipo de usuario que queremos


convertir y T es el tipo en el que queremos convertir C

Operadores de conversin

class 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<double>(a) + 5;

Ambigedades en la conversin

Surgen si hay varias conversiones implcitas 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 si convertir b a Complejo y realizar la suma o convertir a a double, hacer la suma y convertir el resultado a Complejo.

Operador de llamada a funcin



Es el operador ()
Siempre debe ser denido dentro de una clase
x (y, z) se interpreta como x.operator (y, z)
til para implementar callbacks (pasar cdigo Tambin para el acceso a matrices
multidimensionales
como argumento de una funcin). Los denominados Objetos Funcin

Operador de llamada a funcin



class 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 las funciones operator new y operator new[]:

void* operator new (size_t tamao);
void* operator new[] (size_t tamao);

Estas funciones reservan y memoria y luego llaman el constructor correspondiente


Se pueden sobrecargar para una clase C:

void* C::operator new (size_t tamao);
void* C::operator new[] (size_t tamao);

Son funciones estticas aunque no se declaren como tal (static), porque se invocan antes que el constructor
Primero se busca en la clase (y clases base) y luego la global

Operador new

void* 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 << Error reservando memoria. << endl;



exit(-1);

}


memset (p, c, tam);

return p;
}

Operador delete

Al liberar memoria con delete y delete[] se invoca a las funciones operator delete y operator delete[]:

void operator delete (void*);
void operator delete[] (void*);

Estas funciones llaman al destructor y luego liberan la memoria del objeto


Se puede sobrecargar para una clase C:

void C::operator delete (void*, [size_t]);
void C::operator delete[] (void*, [size_t]);

Son funciones estticas aunque no se declaren como tal (static), porque se invocan despus del destructor
Primero se busca en la clase (y clases base) y luego la global

Operador delete



void Vector::operator delete (void* p, size_t tam) {

if (p)

memset (p, 0, tam);

free (p);
}


void Vector::operator delete[] (void* p, size_t tam) {

if (p)

memset (p, 0, tam);

free (p);
}

ndice

Sobrecarga de Funciones
Sobrecarga de Operadores
Entrada/Salida sobre streams bsicos
Entrada/Salida sobre streams de chero
Entrada/Salida sobre streams de cadena

Visin General de la E/S en C++



Streams y Buffers
Especializaciones segn el tipo de operacin y el origen/destino de los datos

Clases istream y ostream



Derivan de la clase ios
Deben ser conectadas a un buffer (del tipo que cin y cout son de tipo istream y ostream
Normalmente, para hacer E/S sobre cheros o Para usarlas: #include <iostream>

sea)

cadenas se usan las clases especializadas, pero se podran usar estas clases bsicas

Clases istream y ostream



Los Manipuladores nos permiten cambiar las Son funciones especialmente diseadas para
que representa el stream
opciones de formato de los streams (#include <iomanip>)
trabajar junto con los operadores de insercin (<<) y extraccin (>>)

Se modica el formato encadenndolos al objeto


cout << hex << showbase << 20 << endl;

Clases istream y ostream



Manipuladores sin parmetros:
(no)boolapha: Mostrar booleanos como true y false (no)showbase: Mostrar prejo de tipo (0x, 0, etc.) (no)showpoint: Forzar la escritura del punto decimal (no)showpos: Forzar la escritura de un + para valores positivos (no)skipws: Permite ignorar caracteres de espaciado (no)unitbuf: Forzar el vaciado del buffer tras cada operacin (no)uppercase: Mostrar caracteres alfabticos en maysculas dec, hex, oct: Cambiar base (decimal, hexadecimal y octal) xed, scientic: Usar notacin de coma ja o cientca internal, left, right: Alinear el texto endl, ends, ush: Finalizar lnea, cadena y vaciar buffer

Clases istream y ostream



Manipuladores con parmetros
setprecision (int): Fija la precisin en coma otante setw (int): Fija el tamao de un campo (que se rellena


automticamente en caso de ser necesario) setll (char): Selecciona el carcter para el relleno setbase (int): Fija la base numrica a usar (8, 10 16) setiosags (mask): Fija cualquiera de los anteriores ags resetiosags (mask): Reinicia los ags a los valores por defecto
Manipuladores sin parmetros: mtodos setf y unsetf
Manipuladores con parmetros: mtodos propios (ll, width, precision, etc.)

Otra forma de hacer lo mismo



Clases istream y ostream



Ejemplos

cout << xed << setprecision(5) << setw(10)

<< setll(*) << 2.87 << endl;

cout.setf(ios::xed);
cout.precision(5);
cout.width(10);
cout.ll(*);
cout << 2.87 << endl;

Ambas imprimen el mismo resultado


***2.87000


Clase ostream

Permite hacer operaciones de escritura con y sin Sin formato: put y write
Con formato: operator<<
Permite manejar distintas situaciones de error
Tambin se puede posicionar el puntero de
formato

escritura en posiciones determinadas del ujo de salida


Clase ostream

La sobrecarga del operador de insercin permite
realizar escritura con formato

Se puede sobrecargar para cualquier tipo



ostream& operator<< (ostream& os, const T& data)

Y usar los manipuladores vistos anteriormente


Clase ostream

El mtodo put permite escribir un carcter en el
stream

El mtodo write permite escribir n caracteres de


un array en el stream



ostream& put (char ch)

El mtodo ush fuerza el vaciado del buffer


asociado al stream



ostream& ush ()



ostream& write (const char* pch, int n)

Clase ostream

El mtodo tellp permite obtener la posicin en
el stream de salida (principalmente cheros)


pos_type tellp ()

Los mtodos seekp permiten cambiar la posicin


de escritura en relacin a la posicin actual


ostream& seekp (pos_type pos)

o en relacin a una posicin de referencia




ostream& seekp (off_type des, ios_base::seekdir pos)

Clase ostream

Ejemplos:



const char* cadena = Hola mundo;

cout << cadena << endl;

cout.write (cadena, 10);
cout.write (\n, 1);
cout.ush ();

for (unsigned i = 0; i < 10; i++)

cout.put (cadena[i]);
cout.put (\n);
cout.ush ();

Clase istream

Permite realizar operaciones de lectura con y sin Sin formato: get, getline, read, ignore, peek, Con formato: operator>>
Al igual que la clase ostream, permite gestionar
errores y reposicionar el puntero de lectura
gcount, unget, putback
formato:

Clase istream

La sobrecarga del operador de extraccin Se puede sobrecargar para cualquier tipo
Y usar los manipuladores vistos anteriormente
(aunque algunos pueden tener sentido nicamente para la clase ostream)


istream& operator>> (istream& is, T& data)

permite realizar lectura con formato


Clase istream

El mtodo get permite leer un carcter del
stream:

El mtodo getline permite leer una lnea, con una El mtodo read permite leer n caracteres


istream& read (char* ch, int n)

istream& getline (char* ch, int n, char delim = \n)


istream& get (char& ch)

longitud mxima hasta encontrar un delimitador


Clase istream

El mtodo ignore extrae y descarta una cadena

istream& ignore (int n = 1, int delim = eof ())

de hasta n caracteres, mientras no encuentre un delimitador dado


El mtodo peek devuelve el siguiente carcter


del stream sin extraerlo


int peek () const

Clase istream

El mtodo gcount devuelve el nmero de

int gcount () const

caracteres ledos en la ltima extraccin sin formato


El mtodo unget devuelve el ltimo carcter


extrado al stream


istream& unget ()

El mtodo putback devuelve c al stream




istream& putback (char c)

Clase istream

El mtodo tellg permite obtener la posicin en el
stream de entrada (principalmente cheros)


pos_type tellg ()

Los mtodos seekg permiten cambiar la posicin


de lectura en relacin a la posicin actual


istream& seekg (pos_type pos)

o en relacin a una posicin de referencia




istream& seekg (off_type des, 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 << cin.gcount() << endl; // cad2= Hola mundo . Imprime 10
cin.ignore (10, '.'); // Ignora cruel.
cin.putback('!'); // Inserta ! en el stream
cin >> cad;


// cad= !Adios!

Clase iostream

Clase derivada tanto de istream como de ostream
Proporciona acceso de lectura/escritura a Presenta los mismos mtodos que las clases de
las que deriva
streams

Gestin de errores

Los streams manejan 4 bits de error:


eofbit: Se alcanz el nal del chero en una operacin de E/S
failbit: El mtodo de E/S fall
badbit: Hubo un problema con el stream al realizar la operacin
goodbit: Ninguno de los anteriores bits est activado

Los mtodos eof, fail, bad y good devuelven el


valor de estos bits

ndice

Sobrecarga de Funciones
Sobrecarga de Operadores
Entrada/Salida sobre streams bsicos
Entrada/Salida sobre streams de Entrada/Salida sobre streams de cadena

chero

E/S sobre streams de chero


Proporcionada por el chero de cabecera:


#include <fstream>

Provee de las clases ofstream (salida), ifstream Distintos modos para abrir un chero:
El chero se puede abrir en el constructor o con
el mtodo open

ios::in, ios::out, ios::trunc, ios::app, ios::binary, ios::ate

(entrada) y fstream (entrada/salida)


Mtodos de apoyo

El mtodo eof indica si se alcanz el nal del
chero:






bool eof () const

El mtodo is_open indica si existe un chero


abierto asociado con el stream






bool is_open () const

El mtodo close cierra el chero abierto y lo


desliga del stream





bool close ()

Clase ofstream

Clase derivada de ostream especializada en El chero se puede abrir al construir un objeto
de tipo ofstream o con el mtodo open

ofstream (const char* nombre_chero,

ios_base::openmode modo = ios::out | ios::trunc)
void open (const char* nombre_chero,

ios_base::openmode modo = ios::out | ios::trunc)

realizar escrituras sobre cheros


Clase ofstream

Ejemplo:


ofstream of ( chero.txt");
of.write ("Hola mundo\n", 11);
of << "Adios mundo" << endl;

for (char c = 'a'; c <= 'z'; c++) {
of.put(c);
of << ", ";
}
of << endl;

of.close();

Clase ifstream

Clase derivada de istream especializada en El chero se puede abrir al construir un objeto
de tipo ifstream o con el mtodo open

ifstream (const char* nombre_chero,

ios_base::openmode modo = ios::in)
void open (const char* nombre_chero,

ios_base::openmode modo = ios::in)

realizar lecturas desde cheros


Clase ifstream

Ejemplo:

ifstream f ( chero.txt");
char buffer[100];

f.getline (buffer, 100);
cout << buffer << endl;
f.ignore(100, '\n');

for (unsigned i = 1; i <= 26; i++) {

char c;

f >> c;

cout << c << endl;

f.ignore(2, ',');
}

Clase fstream

Combina las funcionalidades de ifstream y El chero se puede abrir al construir un objeto
de tipo fstream o con el mtodo open

fstream (const char* nombre_chero,

ios_base::openmode modo = ios::in | ios::out)
void open (const char* nombre_chero,

ios_base::openmode modo = ios::in | ios::out)

ofstream

E/S usando Registros



Podemos escribir estructuras de datos complejas
Los datos se guardan en formato binario, en Podemos hacerlo con los mtodos read y write
Requiere una conversin de la estructura en un Uso de reinterpret_cast<char*>()

array de caracteres
lugar de escribirse carcter a carcter

E/S usando Registros



struct nodo_agenda { char nombre[30]; char direccion[40]; long telefono;
};

nodo_agenda persona;
cin.getline (30, persona.nombre);
cin.getline (40, persona.direccion);
cin >> persona.telefono;

ofstream ofs (agenda);
ofs.write (reinterpret_cast<char*>(&persona), sizeof(nodo_agenda));
ofs.close ();

ndice

Sobrecarga de Funciones
Sobrecarga de Operadores
Entrada/Salida sobre streams bsicos
Entrada/Salida sobre streams de chero
Entrada/Salida sobre streams de
cadena

La clase String

Clase que sirve para trabajar con cadenas de Tambin almacena el tamao de la cadena
Gestiona automticamente la memoria dinmica Facilita las operaciones ms habituales con Hace falta incluir el siguiente chero de
cabecera: #include <string>
cadenas de caracteres
asociada a la cadena
caracteres

La clase String

Cmo construimos un objeto de tipo string:

string cad1; // Construye una cadena vaca
string cad2 (cad1); // Constructor de copia
char arr[] = Hola mundo);
string cad3 (arr); // Constructor a partir de un array de char

Podemos consultar el tamao de una cadena:



cout << El tamano de cad1 es: << cad1.size() << endl;

Podemos acceder carcter a carcter:



for (unsigned i = 0; i < cad1.size(); i++)

cout << cad1[i];

La clase String

Podemos asignar cadenas sin miedo (la memoria
la gestiona la propia clase):

string cad1 = Hola mundo;
string cad2 = Adios mundo;
cad2 = cad1;

Si nos interesa, podemos recuperar el array de


caracteres asociado al objeto string

string cad1 = abcdefgh;
const char* arr1 = cad1.c_str(); // S aade \0
const char* arr2 = cad1.data(); // No aade \0
char buffer[80];
cad1.copy (buffer, cad1.size(), 0);

La clase String

Tambin podemos realizar las operaciones de Se comparan letra por letra y se usa el orden
alfabtico


string str1 = abcdefg, str2 = Abcdefg;
if (str1 < str2)

cout << str1 << endl;
else

cout << str2 << endl;

comparacin habituales: ==, !=, <, >, <= y >=


La clase String

Se pueden insertar caracteres en una cadena:

string cad = Hola;
cad += mundo; // Aade mundo al nal
cad.append ( cruel); // Aade cruel al nal
cad.insert (11, nada ); // Inserta nada en la posicin 11
cout << cad << endl; // Imprime Hola mundo nada cruel;

Y concatenar dos cadenas:


string cad1 = Hola;


string cad2 = mundo;
string cad3 = cad1 + cad2;
cout << cad3 << endl; // Imprime Hola mundo

La clase String

Tambin podemos buscar subcadenas:

int pos;
string cad = abcdefghijk;
pos = cad.nd (efg); // pos = 4
pos = cad.nd (i); // pos = 8

Reemplazar subcadenas:
Y extraer subcadenas:

cad.replace (cad.nd (efg), 2, zyx ); // cad = abcd zyx ghijk



string cad1 = Esto es una cadena;
string cad2 = cad1.substr (12, 6); // cad2 = cadena

Entrada/Salida sobre streams de cadena


Proporcionada por el chero de cabecera: Provee de las clases ostringstream (salida),


#include <sstream>

Permite realizar operaciones de E/S sobre

istringstream (entrada) y stringstream (e/s)


Se pueden usar los mtodos de las clases bsicas


istream, ostream y stream (respectivamente)

objetos de tipo string (parecido al sprintf de C)


Entrada/Salida sobre streams de cadena


Denen dos mtodos adicionales:


Permiten recuperar e inicializar la cadena Tambin se les puede asociar una cadena en el
constructor


istringstream (const string& str,


ios_base::openmode modo = ios_base::in)



string str ( ) const
void str (const string & s)

asociada al stream

Ejemplo con ostringstream




ostringstream buffer;

string nombre = "Antonio";
int edad = 27;
char acion[] = "leer";

buffer << "Hola. Me llamo " << nombre << ", tengo " << edad

<< " tacos y me gusta " << acion << endl;

cout << buffer.str() << endl;

Ejemplo con istringstream




string nombre2;
int edad2 = 0;
char acion2[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 >> acion2; // acion2 = leer

También podría gustarte