Documente Academic
Documente Profesional
Documente Cultură
Operadores redefinibles
operador
Nombre
Tipo
Coma
Binary
NOT lgico
Unario
!=
Desigualdad
Binary
Mdulo
Binary
%=
Asignacin y mdulo
Binary
&
Binary
&
Direccin de
Unario
&&
AND lgico
Binary
&=
Binary
()
Llamada a funcin
()
Operador de conversin
Unario
Multiplicacin
Binary
Desreferencia de puntero
Unario
*=
Asignacin y multiplicacin
Binary
Adicin
Binary
Unario ms
Unario
++
Incremento 1
Unario
+=
Asignacin y suma
Binary
Resta
Binary
Negacin unaria
Unario
Decremento 1
Unario
Asignacin y resta
Binary
>
Seleccin de miembro
Binary
>*
Seleccin de puntero a
miembro
Binary
Divisin
Binary
/=
Asignacin y divisin
Binary
<
Menor que
Binary
<<
Desplazamiento a la izquierda
Binary
<<=
Asignacin y desplazamiento a
la izquierda
Binary
<=
Binary
Asignacin
Binary
==
Igualdad
Binary
>
Mayor que
Binary
>=
Binary
>>
Desplazamiento a la derecha
Binary
>>=
Asignacin y desplazamiento a
la derecha
Binary
[]
Subndice de matriz
OR exclusivo
Binary
^=
Asignacin y OR exclusivo
Binary
Binary
|=
Binary
||
OR lgico
Binary
Complemento a uno
Unario
delete
Delete
new
New
conversion operators
operadores de conversin
Unario
// rules_for_operator_overloading.cpp
class Point
{
public:
Point operator<( Point & ); // Declare a member
operator
6)
// overload.
7)
// Declare addition operators.
8)
friend Point operator+( Point&, int );
9)
friend Point operator+( int, Point& );
10) };
11)
14) }
var++;
++var;
No se puede confiar en esta identidad para los tipos de clase que sobrecargan
operadores. Adems, algunos requisitos implcitos en el uso de estos
operadores para los tipos bsicos se relajan para los operadores
sobrecargados. Por ejemplo, el operador de suma o asignacin, +=, requiere
que el operando izquierdo sea un valor L cuando se aplica a los tipos bsicos;
este requisito no existe cuando se sobrecarga el operador.
Nota
Por coherencia, a menudo es mejor seguir el modelo de los tipos integrados al
definir operadores sobrecargados. Si la semntica de un operador
sobrecargado difiere mucho de su significado en otros contextos, puede ser
ms confusa que til
Los operadores que se muestran en la tabla siguiente no se pueden
sobrecargar. La tabla incluye los smbolos de preprocesador # y ##.
Operadores no redefinibles
Operator
Name
Seleccin de miembro
.*
::
Resolucin de mbito
?:
Condicional
##
Concatenacin de preprocesadores
Ejemplo
En el ejemplo siguiente se sobrecarga el operador + para sumar dos nmeros
complejos y se devuelve el resultado.
// operator_overloading.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
struct Complex {
Complex( double r, double i ) : re(r), im(i) {}
Complex operator+( Complex &other );
void Display( ) {
cout << re << ", " << im << endl; }
private:
double re, im;
};
// Operator overloaded using a member function
Complex Complex::operator+( Complex &other ) {
return Complex( re + other.re, im + other.im );
}
int main()
Complex
Complex
Complex
{
a = Complex( 1.2, 3.4 );
b = Complex( 5.6, 7.8 );
c = Complex( 0.0, 0.0 );
c = a + b;
c.Display();
}
La herencia
Se entiende por herencia el proceso por el que un objeto puede tomar
caractersticas de otro objeto.
La herencia se puede usar de dos formas:
1. Cuando una clase escrita no llega a cubrir las necesidades que exige un
determinado problema, se puede retocar el cdigo cambiando las
caractersticas que se requieren, e ignorando el resto.
Esto permite una programacin rpida. Esto es una forma de reutilizacin del
cdigo.
2. Se expresa un determinado problema como una jerarqua de clases, donde
existe una clase base de la que se derivan otras subclases. La interfaz de la
clase base es comn a todas las clases derivadas
CONSTRUCTORES Y DESTRUCTORES EN LA HERENCIA
Los constructores y destructores no son heredados por las clases derivadas.
Sin embargo, una instancia de una clase derivada contendr todos los
miembros de la clase base, y stos deben ser iniciados. En consecuencia, el
constructor dela clase base debe ser llamado por el constructor de la clase
derivada.
CONVERSIONES ENTRE LAS CLASES BASE Y DERIVADAS
Dado que una clase derivada se puede entender como un sper conjunto de la
clase base, que va a contener todos los miembros de la clase base, una
instancia de la clase derivada se puede emplear de forma automtica como si
fuera una instancia de la clase base. El caso contrario no es cierto, no se puede
tratar un objeto de la clase base como si fuera uno bjeto de una clase derivada,
ya que el objeto de la clase base no tiene todos los miembros de la clase
derivada.
TIPOS DE HERENCIA
Es la propiedad con la cual una clase derivada puede tener ms de una clase
base. Es ms adecuada para definir objetos que son compuestos, por
naturaleza, tales como un registro personal, un objeto grfico.
La sintaxis de la herencia mltiple es una extensin de la utilizada para la
herencia simple. La manera deexpresar este tipo de herencia es mediante una
lista de herencia, que consta de las clases de las que se hereda separadas por
comas.
CONSTRUCTORES Y DESTRUCTORES EN HERENCIA MLTIPLE
El uso de funciones constructor y destructor en clases derivadas es ms
complejo que en una clase simple. Al crear clases derivadas con una sola clase
base, se observa que el constructor dela clase base se llama siempre antes que
el constructor de la clase derivada. Adems se dispone de un mecanismo para
pasar los valores de los parmetros necesarios al constructor base desde el
constructor de la clase derivada.
As, la sentencia siguiente pasa el puntero a carcter x y el valor del entero y a
la clase base: derivada (char *x, int y, double z): base(x, y)
Este mtodo se expande para efectuar ms de una clase base.
Las entencia: derivada (char *x,int y, double z): base1(x),base2(y)
AMBIGEDADES EN LA HERENCIA MLTIPLE
En la herencia mltiple aparecen ambigedades, como en el ejemplo de
encima: si la clase Msico heredaba de Persona y Trabajador, y la clase
Trabajador heredaba de Persona.
Existiran las siguientes reglas:
Msico Estudiante: Persona, Msico, Trabajador
Msico: Persona, Trabajador
Trabajador: Persona
Si un compilador est mirando la clase Msico Estudiante necesita saber si
debe juntar las caractersticas iguales o si deben estar separadas. Por ejemplo,
tendra sentido unir las caractersticas "Edad" de Persona para Msico
POLIMORFISMO
Habilidad de un mismo objeto para tomar diferentes formas;
En too es la propiedad que tienen objetos pertenecientes a diferentes clases de
poder responder a un mismo mensaje de diferentes formas;
Para que la ligadura dinmica tenga efecto en una funcin particular, C++
necesita que se use la palabra reservada virtual cuando se declara la funcin en
la clase base. La ligadura en tiempo de ejecucin funciona uncamente con las
funciones virtual es, y slo cuando se est usando una direccin de la clase
base donde exista la funcin virtual, aunque puede ser definida tambin en una
clase base anterior.
Para crear una funcin miembro como virtual, simplemente hay que preceder
a la declaracin de la funcin con la palabra reservada virtual. Slo la
declaracin necesita la palabra reservadavirtual, y no la definicin. Si una
funcin es declarada como virtual, en la clase base, ser entonces virtual en
todas las clases derivadas. La redefinicin de una funcin virtual en una clase
derivada se conoce como overriding.
Hay que hacer notar que slo es necesario declarar la funcin como virtual en
la clase base. Todas las funciones de las clases derivadas que encajen con la
declaracin que est en la clase base sern llamadas usando el mecanismo
virtual. Se puede usar la palabra reservada virtual en las declaraciones de las
clases derivadas (no hace ningn mal), pero es redundante y puede causar
confusin.
Para conseguir el comportamiento deseado de Instrument2.cpp, simplemente
hay que aadir la palabra reservada virtual en la clase base antes de play().
//: C15:Instrument3.cpp
// Late binding with the virtual keyword
#include <iostream>
using namespace std;
enum note { middleC, Csharp, Cflat }; // Etc.
class Instrument {
public:
virtual void play(note) const {
cout << "Instrument::play" << endl;
}
};
// Wind objects are Instruments
// because they have the same interface:
class Wind : public Instrument {
public:
// Override interface function:
void play(note) const {
cout << "Wind::play" << endl;
}
};
void tune(Instrument& i) {
// ...
i.play(middleC);
}
int main() {
Wind flute;
tune(flute); // Upcasting
} ///:~
new Brass,
};
int main() {
Wind flute;
Percussion drum;
Stringed violin;
Brass flugelhorn;
Woodwind recorder;
tune(flute);
tune(drum);
tune(violin);
tune(flugelhorn);
tune(recorder);
f(flugelhorn);
} ///:~
Se puede ver que se ha aadido otro nivel de herencia debajo de Wind, pero el
mecanismovirtual funciona correctamente sin importar cuantos niveles haya.
La funcin adjust() no est redefinida (override) por Brass y Woodwind.
Cuando esto ocurre, se usa la definicin ms "cercana" en la jerarqua de
herencia - el compilador garantiza que exista alguna definicin para una
funcin virtual, por lo que nunca acabar en una llamada que no est enlazada
con el cuerpo de una funcin (lo cual sera desatroso).
El array A[] contiene punteros a la clase base Instrument, lo que implica que
durante el proceso de inicializacin del array habr upcasting. Este array y la
funcin f() sern usados en posteriores discusiones.
En la llamada a tune(), el upcasting se realiza en cada tipo de objeto, haciendo
que se obtenga siempre el comportamiento deseado. Se puede describir como
"enviar un mensaje a un objeto y dejar al objeto que se preocupe sobre qu
hacer con l". La funcin virtual es la lente a usar cuando se est analizando
un proyecto: Dnde deben estar las clases base y cmo se deseaextender el
programa? Sin embargo, incluso si no se descubre la interfaz apropiada para la
clase base y las funciones virtuales durante la creacin del programa, a
menudo se descubrirn ms tarde, incluso mucho ms tarde cuando se desee
ampliar o se vaya a hacer funciones de mantenimiento en el programa. Esto no
implica un error de anlisis o de diseo; simplemente significa que no se
conoca o no se poda conocer toda la informacin al principio. Debido a la
fuerte modularizacin de C++, no es mucho problema que esto suceda porque
los cambios que se hagan en una parte del sistema no tienden a propagarse a
otras partes como sucede en C.
MANEJO DE EXCEPCIONES
Las excepciones son en realidad errores durante la ejecucin. Si uno de esos
errores se produce y no implementamos el manejo de excepciones, el
programa sencillamente terminar abruptamente. Es muy probable que si hay
ficheros abiertos no se guarde el contenido de los buffers, ni se cierren,
adems ciertos objetos no sern destruidos, y se producirn fugas de memoria.
En programas pequeos podemos prever las situaciones en que se pueden
producir excepciones y evitarlos. Las excepciones ms habituales son las de
peticiones de memoria fallidas.
Veamos este ejemplo, en el que intentamos crear un array de cien millones de
enteros:
#include <iostream>
using namespace std;
int main() {
int *x = NULL;
int y = 100000000;
x = new int[y];
x[10] = 0;
cout << "Puntero: " << (void *) x << endl;
delete[] x;
return 0;
}
#include <iostream>
using namespace std;
int main() {
int *x = 0;
int y = 100000000;
x = new int[y];
if(x) {
x[10] = 0;
cout << "Puntero: " << (void *) x << endl;
delete[] x;
} else {
cout << "Memoria insuficiente." << endl;
}
return 0;
}
#include <iostream>
using namespace std;
int main() {
try {
throw 'x'; //
}
catch(int c) {
cout << "El valor de c es: " << c << endl;
}
catch(...) {
cout << "Excepcin imprevista" << endl;
}
return 0;
}
Templetes en C++
Los templetes son muy importantes en el desarrollo de software con C++. Es
sin duda una de las caractersticas ms importantes (si no es la ms
importante) de este lenguaje. Nos permite escribir cdigo genrico que puede
ser usado con varios tipos de datos. Sin templetes, se tendran que reescribir
muchas funciones y clases. Tomemos el siguiente ejemplo de una funcin que
retorna el mximo de dos valores.
int max(int x, int y)
{
return (x < y) ? y : x;
}
float max(float x, float y)
{
return (x < y) ? y : x;
}
Como podemos ver, sin templetes dos funciones que tienen el mismo cuerpo
se tienen que reescribir para que funcione con varios tipos. Veamos la misma
funcin usando templetes.
template <typename T>
T max(T x, T y)
{
return (x < y) ? y : x;
}
Esta funcin funciona con cualquier tipo que se pueda comparar con el
operador <. Funciona hasta con tu propia clase si ella tiene el
operador< implementado. Tambin se puede tener templetes para clases.
Clases como std::vector y std::list son templetes y nos permiten usarlas para
cualquier tipo que queramos. Veamos un ejemplo de una clase tmplate.
template <typename T>
class Puntero
{
T* _ptr;
public:
explicit Puntero(T* ptr = 0) : _ptr(ptr) {}
~Puntero() { delete _ptr; }
// implementamos estos operadores para que la clase actue
como puntero
T& operator*() { return *_ptr; }
T* operator->() { return _ptr; }
};
int main()
{
Puntero<int> puntero_int(new int);
*puntero_int = 10;
Puntero<bool> puntero_bool(new bool);
*puntero_bool = true;
}