Publicado el 3 de Mayo del 2017
1.042 visualizaciones desde el 3 de Mayo del 2017
511,5 KB
78 paginas
Sobrecarga de Operadores y
E/S en C++
Antonio LaTorre de la Fuente
Índice
• Sobrecarga de Funciones
• Sobrecarga de Operadores
• Entrada/Salida sobre streams básicos
• Entrada/Salida sobre streams de fichero
• 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
prototipo: número y/o tipo de argumentos
operación sobre distintos tipos de datos
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;
}
Ambigüedad
• ¿Qué pasa si incluimos en nuestro código…?
unsigned num = 3;
print (num);
• El compilador no sabe a qué función 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: void print(int, std::string)
func_over.cc:8: note: void print(double)
Ambigüedad
• Se soluciona usando static_cast
unsigned num = 3;
print (static_cast<double>(num));
• ¿Qué pasaría si hiciéramos…?
int num = 3;
print (num);
Name Mangling
• Estrategia que usa el compilador para poder
diferenciar 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 en:
int __f_v (void) {return 1;}
int __f_i (int) {return 0;}
void __g_v (void) {int i = __f_v (), j = __f_i (0);}
Índice
• Sobrecarga de Funciones
• Sobrecarga de Operadores
• Entrada/Salida sobre streams básicos
• Entrada/Salida sobre streams de fichero
• Entrada/Salida sobre streams de cadena
Operadores en C++
• Lista de operadores válidos en C++
+
~
++
+=
-
!
--
-=
*
,
<<
*=
/
=
>>
/=
%
<
==
%=
^
>
!=
^=
<<=
>>=
[]
• Se declaran de la siguiente forma:
()
->
->*
&
<=
&&
&=
|
>=
||
|=
new
delete
tipo operator operador([argumentos])
Operadores en C++
• Hay algunos operadores especiales que no
pueden ser sobrecargados
•
•
•
• ?: (operador condicional)
• sizeof (tamaño de)
• typeid (identificación del tipo)
. (selección de un miembro)
:: (resolución de ámbito)
.* (selección de un miembro referenciado por un puntero)
Precedencia de Operadores
• Los operadores en C++ tienen distinta
• Lo mejor es usar () en casa de no estar seguro
• Tabla de precedencias:
precedencia, y a veces no es obvio
Inglés: http://www.cplusplus.com/doc/tutorial/operators/
Español: http://es.wikipedia.org/wiki/Operadores_en_C_y_C%2B%2B
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 explícita
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 métodos de una clase, uno
de los argumentos es implícito (aquél 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: Números Complejos
class Complejo {
public:
Complejo (double r, double i) : real(r), imag(i) {}
…
private:
double real;
double imag;
}
Operadores Aritméticos
• Suma de 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;
}
Operadores Relacionales
• Comparación de números 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:
Post-incremento:
C C::operator++()
C C::operator++(int x)
Complejo Complejo::operator++() {
real += 1;
return *this;
}
acceder a los elementos privados de esa clase
Funciones “Amigas”
• Son funciones ajenas a una clase que pueden
• Ejemplo:
• Tenemos dos clases: Vector y Matriz
• Queremos definir el producto vectorial entre
• El contenido de los objetos es privado
ambas clases
Funciones “Amigas”
class Vector {
class Matriz {
friend operator* (const Matriz&
matriz, const Vector& vector);
friend operator* (const Matriz&
matriz, const Vector& vector);
public:
…
private:
int size;
int* data;
}
public:
…
private:
int rows, columns;
int** data;
}
Vector operator* (const Matriz& matriz, const Vector& vector) {…}
Operadores de asignación
• 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++)
return *this;
data[i] = vector.data[i];
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 inserción y extracción
• Permiten escribir / leer en la salida / entrada
• Hay que sobrecargar los operadores:
estándar
ostream& operator<< (ostream& os, const T& arg)
istream& operator>> (istream& is, T& arg)
• Podemos hacer que estos métodos sean amigos
de nuestra clase o implementar un método
público que imprima los datos
Operadores de inserción y extracción
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 Indexación
• Es el operador []
• Es un operador binario y de clase: recibe el
• Útil, p.ej., para acceso seguro a datos:
objeto donde se aplica y el índice facilitado
int Vector::operator[] (int i) {
return data[i];
if (i >= 0 && i < this->size)
else {
}
cout << “Posición incorrecta: “ << i << endl;
return 0;
}
Conversión de tipos
• Hay dos posibilidades para llevar a cabo
conversiones entre tipos definidos por el
usuario:
• Los constructores de conversión
• Los operadores de conversión
• Son útiles para hacer, por ejemplo:
Complejo a (2, 3), b (0, 0);
b = a + 5;
Constructores de conversión
• Hay que añadir un constructor que nos permita
crear el objeto a partir de un objeto del tipo que
queramos 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;
tipo de usuario a otro tipo (de usuario o no)
Operadores de conversión
• Se usan para proporcionar una conversión de un
• Tiene la sintaxis:
• Donde C es el tipo de usuario que queremos
convertir y T es el tipo en el que queremos
convertir C
C::operator T();
Operadores de conversión
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;
Ambigüedades en la conversión
Surgen 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 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 función
• Es el operador ()
• Siempre debe ser definido dentro de una clase
• x (y, z) se interpreta como x.operator (y, z)
• Útil para implementar callbacks (pasar código
Comentarios de: Sobrecarga de Operadores y E/S en C++ (0)
No hay comentarios