Вы находитесь на странице: 1из 15

Los operadores de Java son muy parecidos en estilo y funcionamiento a los de C.

Tanto C, como C++, como Java, proporcionan un conjunto de operadores para poder realizar acciones sobre uno o dos operandos. Un operador que acta sobre un solo operando es un operador unario, y un operador que acta sobre dos operandos es un operador binario. Algunos operadores pueden funcionar como unarios y como binarios, el ejemplo ms claro es el operador - (signo menos). Como operador binario, el signo menos, el cual hace que el operando de la derecha sea sustraido al operando de la izquierda; como operador unario hace que el signo algebraico del operando que se encuentre a su derecha sea cambiado. En la siguiente tabla aparecen los operadores que se utilizan en Java, por orden de precedencia: . ++ ! * + << < & && ? : = [] -~ / >> > ^ || op= () instanceof % >>> <= | (*= >= == !=

/=

%=

+=

-=

etc.) ,

Los operadores numricos se comportan como esperamos: int + int = int Los operadores relacionales devuelven un valor booleano. Para las cadenas, se pueden utilizar los operadores relacionales para comparaciones adems de + y += para la concatenacin: String nombre = "nombre" + "Apellido"; El operador = siempre hace copias de objetos, marcando los antiguos para borrarlos, y ya se encargar el garbage collector de devolver al sistema la memoria ocupada por el objeto eliminado. Java, a diferencia de C++, no soporta la sobrecarga de operadores. Esto significa que no es posible redefinir el entorno en el que acta un operador con respecto a los objetos de un nuevo tipo que el programador haya definido como propios. Un caso interesante, que se sale de la afirmacin anterior, es el operador + (signo ms), que se puede utilizar para realizar una suma aritmtica o para concatenar cadenas (Java lo sobrecarga internamente!). Cuando el signo ms se utiliza en esta ltima forma, el operando de la derecha se convierte automticamente en una cadena de caracteres antes de ser concatenada con el operando que se encuentra a la izquierda del operador +. Esto asume que el compilador sabe que el operando de la derecha es capaz de soportar la conversin. Y ese conocimiento lo tiene porque comprueba todos los tipos primitivos y muchos de los tipos internos que se utilizan. Obviamente, el compilador no sabe absolutamente nada de los tipos que haya definido el programador. A continuacin se detallan algunos de los operadores que admite Java y que se suelen agrupar en operadores aritmticos, relacionales y condicionales, operadores lgicos y que actan sobre bits y,

finalmente, operadores de asignacin. Operadores Aritmticos Java soporta varios operadores aritmticos que actan sobre nmeros enteros y nmeros en coma flotante. Los operadores binarios soportados por Java son: + * / % suma los operandos resta el operando de la derecha al de la izquierda multiplica los operandos divide el operando de la izquierda entre el de la derecha resto de la divisin del operando izquierdo entre el derecho

Como se ha indicado anteriormente, el operador ms (+), se puede utilizar para concatenar cadenas, como se observa en el ejemplo siguiente: "miVariable tiene el valor " + miVariable + " en este programa" Esta operacin hace que se tome la representacin como cadena del valor de miVariable para su uso exclusivo en la expresin. De ninguna forma se altera el valor que contiene la variable. En C++ no se soporta la concatenacin de cadenas con el operador ms (+); hay que utilizar la funcin strcat() para poder concatenar dos cadenas y el uso de esta funcin puede resultar peligroso porque no hay proteccin contra el traspaso de los lmites del array que se utiliza como destino de la cadena concatenada. El operador mdulo (%), que devuelve el resto de una divisin, a diferencia de C++, en Java funciona con tipos en coma flotante adems de con tipos enteros. Cuando se ejecuta el programa que se muestra en el ejemplo java401.java. La salida que se obtiene por pantalla tras la ejecucin del ejemplo es la que se reproduce a continuacin: %java java401 x mod 10 = 3 y mod 10 = 3.299999999999997 Los operadores unarios que soporta Java son: + ++ -indica un valor positivo negativo, o cambia el signo algebraico suma 1 al operando, como prefijo o sufijo resta 1 al operando, como prefijo o sufijo

En los operadores de incremento (++) y decremento (--), en la versin prefijo, el operando aparece a la derecha del operador, ++x; mientras que en la versin sufijo, el operando aparece a la izquierda del operador, x++. La diferencia entre estas versiones es el momento en el tiempo en que se realiza la operacin representada por el operador si ste y su operando aparecen en una expresin larga. Con la versin prefijo, la variable se incrementa (o decrementa) antes de que sea utilizada para evaluar la expresin en que se encuentre, mientras que en la versin sufijo, se utiliza

la variable para realizar la evaluacin de la expresin y luego se incrementa (o decrementa) en una unidad su valor. Operadores Relacionales y Condicionales Aunque Java y C++ soportan los mismos operadores relacionales, devuelven valores diferentes. Los operadores relacionales en Java devuelven un tipo booleano, true o false; mientras que en C++ devuelven un valor entero, en donde se puede considerar al valor cero como false y a un valor no-cero como true. > >= < <= == != el operando izquierdo es mayor que el derecho el operando izquierdo es mayor o igual que el derecho el operando izquierdo es menor que el derecho el operando izquierdo es menor o igual que el derecho el operando izquierdo es igual que el derecho el operando izquierdo es distinto del derecho

Los operadores relacionales combinados con los operadores condicionales (o lgicos en C++), se utilizan para obtener expresiones ms complejas. Los operadores condicionales que soporta Java son: && || ! expresiones izquierda y derecha son true o la expresin izquierda o al expresin de la derecha son true la expresin de la derecha es false

Los programadores C++ se encontrarn con que Java restringe el uso de estos operadores, porque en C++ la representacin de true y false es muy diferente a Java. En Java, los operandos de estos operadores deben ser tipos booleanos, o expresiones que devuelvan un tipo booleano, mientras que en C++ puede ser cualquier tipo entero o expresin que devuelva un tipo entero, sin restricciones. Una caracterstica importante del funcionamiento de los operadores && y ||, tanto en Java como en C++ (y que es pasado a veces por alto, incluso por programadores experimentados) es que las expresiones se evalan de izquierda a derecha y que la evaluacin de la expresin finaliza tan pronto como se pueda determinar el valor de la expresin. Por ejemplo, en la expresin siguiente: ( a < b ) || ( c < d ) si la variable a es menor que la variable b, no hay necesidad de evaluar el operando izquierdo del operador || para determinar el valor de la expresin entera. En casos de complejas y largas expresiones, el orden en que se realizan estas comprobaciones puede ser fundamental, y cualquier error en la colocacin de los operandos puede dar al traste con la evaluacin que se desea realizar y, estos errores son harto difciles de detectar, ya que se debe estudiar concienzudamente el resultado de las expresiones en tiempo de ejecucin para poder detectar el problema. Operadores a Nivel de Bits Java y C, C++ comparten un conjunto de operadores que realizan operaciones sobre un solo bit cada vez. Java tambin soporta el operador >>>, que no existe en C o C++ y, adems, el entorno

en el que se realizan algunas de las operaciones no siempre es el mismo en Java que en los otros lenguajes. Los operadores de bits que soporta Java son los que aparecen en la siguiente tablita:
Operador Uso Operando >> Despl Operando << Despl Operando >>> Despl Operando & Operando Operando | Operando Operando ^ Operando ~Operando Operacin Desplaza bits del operando hacia la derecha las posiciones indicadas (con signo) Desplaza bits del operando hacia la izquierda las posiciones indicadas Desplaza bits del operando hacia la derecha las posiciones indicadas (sin signo) Realiza una operacin AND lgiga entre los dos operandos Realiza una operacin OR lgica entre los dos operandos Realiza una operacin lgica OR Exclusiva entre los dos operandos Complementario del operando (unario)

>> << >>> & | ^ ~

En Java, el operador de desplazamiento hacia la derecha sin signo, rellena los bits que pueden quedar vacos con ceros. Los bits que son desplazados fuera del entorno se pierden. En el desplazamiento a la izquierda, hay que ser precavidos cuando se trata de desplazar enteros positivos pequeos, porque el desplazamiento a la izquierda tiene el efecto de multiplicar por 2 para cada posicin de bit que se desplace; y esto es peligroso porque si se desplaza un bit 1 a la posicin ms alta, el bit 31 o el 63, el valor se convertir en negativo. Operadores de Asignacin El operador = es un operador binario de asignacin de valores. El valor almacenado en la memoria y representado por el operando situado a la derecha del operador es copiado en la memoria indicada por el operando de la izquierda. Al contrario que en C++, el operador de asignacin (ni ningn otro) no se puede sobrecargar en Java. Java soporta toda la panoplia de operadores de asignacin que se componen con otros operadores para realizar la operacin que indique ese operador y luego asignar el valor obtenido al operando situado a la izquierda del operador de asignacin. De este modo se pueden realizar dos operaciones con un solo operador. += >>= -= *= >>>= /= %= &= |= ^= <<=

Por ejemplo, las dos sentencias que siguen realizan la misma funcin: x += y; x = x + y; Y las otras comprobaciones siguen el mismo patrn. C++ no soporta el operador >>>= porque tampoco soporta el operador a nivel de bits de desplazamiento sin signo ( >>>). Operadores Ternario if-then-else

Java, lo mismo que C y C++, soporta este operador ternario. No obstante, la construccin utilizada por este operador es lago confusa, aunque se puede llegar a entender perfectamente cuando uno lee en el pensamiento lo que est escrito en el cdigo. La forma general del operador es: expresion ? sentencia1 : sentencia2 en donde expresion puede ser cualquier expresin de la que se obtenga como resultado un valor booleano, porque en Java todas las expresiones condicionales se evalan a booleano; y si es true entonces se ejecuta la sentencia1 y en caso contrario se ejecuta la sentencia2. La limitacin que impone el operador es que sentencia1 y sentencia2 deben devolver el mismo tipo, y ste no puede ser void. Puede resultar til para evaluar algn valor que seleccione una expresin a utilizar, como en la siguiente sentencia: cociente = denominador == 0 ? 0 : numerador / denominador Cuando Java evala la asignacin, primero mira la expresin que est a la izquierda del interrogante. Si denominador es cero, entonces evala la expresin que est entre el interrogante y los dos puntos, y se utiliza como valor de la expresin completa. Si denominador no es cero, entonces evala la expresin que est despus de los dos puntos y se utiliza el resultado como valor de la expresin completa, que se asigna a la variable que est a la izquierda del operador de asignacin, cociente. En el ejemplo java402.java se utiliza este operador para comprobar que el denominador no es cero antes de evaluar la expresin que divide por l, devolviendo un cero en caso contrario. Hay dos expresiones, una que tiene un denominador cero y otra que no. class java402 { public static void main( String args[] ) { int a = 28; int b = 4; int c = 45; int d = 0; // Utilizamos el operador ternario para asignar valores a // las dos variables e y f, que son resultado de la // evaluacin realizada por el operador int e = (b == 0) ? 0 : (a / b); int f = (d == 0) ? 0 : (c / d); // int f = c / d; System.out.println( "a System.out.println( "b System.out.println( "c System.out.println( "d System.out.println(); System.out.println( "a System.out.println( "c } } El programa se ejecuta sin errores, y la salida que genera por pantalla es la que se reproduce: = = = = " " " " + + + + a b c d ); ); ); );

/ b = " + e ); / d = " + f );

%java java402 a = 28 b = 4 c = 45 d = 0 a / b = 7 c / d = 0 Si ahora cambiamos la lnea que asigna un valor a la variable f, y quitamos este operador, dejndola como: int f = c / d; se producir una excepcin en tiempo de ejecucin de divisin por cero, detenindose la ejecucin del programa en esa lnea. %java java402 java.lang.ArithmeticException: / by zero at java402.main(java402.java:40) Errores comunes en el uso de Operadores Uno de los errores ms comunes que se cometen cuando se utilizan operadores es el uso incorrecto, o no uso, de los parntesis cuando la expresin que se va a evaluar es compleja. Y esto sigue siendo cierto en Java. Cuando se programa en C/C++, el error ms comn es el siguiente: while( x = y ) { // . . . } EL programador intenta realmente hacer una equivalencia (==) en vez de una asignacin. En C/C++ el resultado de esta asignacin siempre ser true si y no es cero, y lo ms seguro es que esto se convierta en un bucle infinito. En Java, el resultado de esta expresin no es un booleano, y el compilador espera un booleano, que no puede conseguir a partir de un entero, as que aparecer un error en tiempo de compilacin que evitar que el programa se caiga al ejecutarlo. Es decir, este error tan comn, para que se d en Java tienen que ser x e y booleanos, lo cual no es lo ms usual. Otro error muy difcil de detectar en C++ es cuando se utiliza el operador unario & cuando la lgica requiere un operador &&; o utilizar el operador unario |, en lugar del operador ||. Este es otro problema difcil de detectar porque el resultado es casi siempre el mismo, aunque slo por accidente. En Java, no ocurre esto y se puede utilizar perfectamente el operador unario & como sinnimo del operador &&, o el operador | como sinnimo de ||; pero si se hace as, la evaluacin de la expresin no concluir hasta que todos los operandos hayan sido evaluados, perdiendo de esta forma las posibles ventajas que podra reportar la evaluacin de izquierda a derecha. Moldeo de Operadores Es lo que se conoce como casting, refirindose a "colocar un molde". Java automticamente cambia el tipo de un dato a otro cuando es pertinente. Por ejemplo, si se asigna un valor entero a una variable declarada como flotante, el compilador convierte automticamente el int a float. El

casting, o moldeo, permite hacer esto explcitamente, o forzarlo cuando normalmente no se hara. Para realizar un moldeo, se coloca el tipo de dato que se desea (incluyendo todos los modificadores) dentro de parntesis a la izquierda del valor. Por ejemplo: void moldeos() { int i = 100; long l = (long)i; long l2 = (long)200; } Como se puede ver, es posible realizar el moldeo de un valor numrico del mismo modo que el de una variable. No obstante, en el ejemplo el moldeo es superfluo porque el compilador ya promociona los enteros a flotantes cuando es necesario automticamente, sin necesidad de que se le indique. Aunque hay otras ocasiones en que es imprescindible colocar el moldeo para que el cdigo compile. En C/C++ el moldeo puede causar autnticos quebraderos de cabeza. En Java, el moldeo es seguro, con la excepcin de cuando se realiza una conversin estrecha, es decir, cuando se quiere pasar de un dato que contiene mucha informacin a otro que no puede contener tanta, en donde se corre el riesgo de perder informacin. Aqu es donde el compilador fuerza a que se coloque un moldeo expreso, indicando al programador que "esto puede ser algo peligroso, as que si quieres que lo haga, dmelo expresamente". Cuando se trata de una conversin ancha, no es necesario el moldeo explcito, ya que el nuevo tipo podr contener ms informacin que la que contiene el tipo original, no ocasionndose ninguna prdida de informacin, as que el compilador puede realizar el moldeo explcitamente, sin la intervencin del programador para confirmar la accin. Java permite el moldeo de cualquier tipo primitivo en otro tipo primitivo, excepto en el caso de los booleanos, en que no se permite moldeo alguno. Tampoco se permite el moldeo de clases. Para convertir una clase en otra hay que utilizar mtodos especficos. La clase String es un caso especial que se ver ms adelante.

Por qu java no soporta la sobre carga de operadores?

java no soporta sobrecarga de operadores , aunque el sistema internamente la utiliza, pero est ocultada al programador, por ejemplo si te fijas al hacer un Int ejemplo=2+1; En java eso es valido y le asigna un 3 a la variable ejemplo la funcionalidad fue sumar, sin embargo en este: String ejemplo="hola"+"mundo"; El operador + se utiliza con otra finalidad : Concatenar , lo ves? Java si usa la sobrecarga de operadores, pero esta oculta para el programador, sea no te permite usarla. Porque? Bsicamente para no llevar a confusin , imagina que defines una clase llamada "sobreEscribe" en la cual sobrecargaras el operador suma y le asinaras tu propia forma de trabajar por ejemplo sumar fracciones y mas tarde defines la clase "fracciones" heredando la clase "sobreEscribe" el resultado seria que en la clase "fracciones" el operador suma cambiara su comportamiento. Si llegase ahora un porgramador externo y revisara la clase fracciones podria confundirse y creer que este operador mantiene el comportamiento normal , para saber que tiene el comportamiento actual tendria que ir a revisar "sobreEscribe", ahora imagina que esta herencia se realiza entre varias clases , seria muy dificil saber si realmente se esta cambiando el comportamiento del operador suma o no. Esta es una de las razones mas fuertes por las cuales Java no soporta

la sobrecarga de operadores basicamente para no llevar a confusion y al fin y al cabo no es necesaria , puedes utilizar tus propios metodos

Qu es la sobrecarga de operadores?

En C++ se pueden hacer operaciones con los tipos bsicos del lenguaje: se pueden sumar enteros, compararlos, etc. Lo siguiente es perfectamente vlido en C++

int a=3; int b=4; int c;

c = a + b;

Si estos tipos no son los bsicos del lenguaje, no se puede hacer sumas con ellos. Por ejemplo, si ClaseC es una clase que tengo definida en C++, el siguiente cdigo dar error.

ClaseC a; ClaseC b; ClaseC c;

c = a + b;

C++ permite que hagamos estas cosas si definimos en algn sitio cmo se suman esas clases. Definiendo cmo se hacen las operaciones, podremos escribir las operaciones con nuestras clases de la misma forma que si se trataran de tipos bsicos del lenguaje.

De hecho podemos definir cualquier operador que nos d C++, desde algunos muy normales como suma, resta, multiplicacin, mayor qu, etc, a otros un poco ms raros como el operador () o el [], de forma que ClaseC[i] o ClaseC(i,j) pueden devolver lo que nosostros queramos.

Sobrecarga del operador suma


Si tenemos una clase ComplejoC que representa un complejo, para poder sumar dos de estas clases simplemente poniendo un +, como con cualquier tipo bsico de C++, debemos sobrecargar el operador +, darle una nueva funcionalidad.

La sobrecarga de un operador suma se hace de la siguiente manera

class ComplejoC { public: // Permite sumar un ComplejoC con un double ComplejoC operator + (double sumando);

// Permite sumar un ComplejoC con un array ComplejoC operator + (const double sumando[]);

// Permite sumar dos ComplejoC entre s. ComplejoC operator + (const ComplejoC &sumando); };

Aqu estamos redefiniendo tres operadores suma para que nos permita sumar a nuestra clase ComplejoC cosas como un double, un array de double (que supondremos contiene dos double, aunque no tenemos forma de comprobarlo) y otra clase ComplejoC .

En estas funciones hemos puesto const en los parmetros para no poder cambiarlos dentro del cdigo. En la tercera funcin pasamos ComplejoC por referencia (el &), para evitar que se hagan copias innecesarias. En la primera funcin no es necesario nada de esto, puesto que es un simple double. En la segunda, ponemos const para no poder modificar el array, pero no es necesaria la referencia, puesto que los arrays son punteros.

A la hora de implementar debemos tener cuidado con los const que hemos puesto. Por ejemplo, en el tercer operador +, recibimos un sumando que es const. El cdigo que implementemos dentro no puede modificar dicho sumando, ni puede llamar a ningn mtodo de ese sumando que no est declarado como const. Si lo intentamos, el compilador dar error. Supongamos que ComplejoC tiene un atributo double x (parte real) y un mtodo dameX() para obtener dicho atributo, este mtodo debe estar declarado const para poder llamarlo desde nuestro operator +. Ms o menos esto:

class ComplejoC { public: // Atencin al const del final. Sin el no podemos llamar a sumando.dameX(). double dameX() const; };

de forma que en el operator + podemos llamar a sumando.dameX().

Una vez implementados estos mtodos, podemos hacer operaciones como

ComplejoC a; ComplejoC b;

// Aprovechando la primera sobrecarga b = a + 1.0;

// Aprovechando la segunda sobrecarga double c[] = {1.0, 2.0}; b = a + c;

// Aprovechando la tercera sobrecarga b = a + b;

Cuando el compilador lee a + 1.0, lo interpreta como a.operator + (1.0), es decir, la llamada al operador suma al que se le pasa como parmetro un double . De la misma forma sucede con los otros dos operadores suma.

Sin embargo, esto nos da un pequeo problema. Qu pasa si ponemos 1.0 + a?. Debera ser lo mismo, pero al compilador le da un pequeo problema. Intenta llamar al mtodo operator + de 1.0, que no existe, puesto que 1.0 ni es una clase ni tiene mtodos. Para solucionar este problema tenemos la sobrecarga de operadores globales.

Sobrecarga de operadores suma globales


Un operador global es una funcin global que no pertenece a ninguna clase y que nos indica cmo operar con uno o dos parmetros (depende del tipo de operador).

En nuestro ejemplo de las sumas, para poder poner los sumandos al revs, deberamos definir las siguientes funciones globales:

ComplejoC operator + (double sumando1, const ComplejoC &sumando2); ComplejoC operator + (double sumando1[], const ComplejoC &sumando2);

Estas funciones le indican al compilador cmo debe sumar los dos parmetros y qu devuelve. Con ellas definidas e implementadas, ya podemos hacer

b = 1.0 + a;

// c era un array de double b = c + a;

Esta sobrecarga es especialmente til cuando tratamos con una clase ya hecha y que no podemos modificar. Por ejemplo, cout es de la clase ostream y no podemos modificarla, sin embargo nos sera de utilidad sobrecargar el operador << de ostream de forma que pueda escribir nuestros nmeros complejos. La siguiente llamada nos dar error mientras no redefinamos el operator << de ostream .

cout << a << endl;

// a es un ComplejoC

Con la sobrecarga de operadores globales podemos definir la funcin

ostream &operator << (ostream &salida, const ComplejoC &valor);

Con esta funcin definida, el complejo se escribir en pantalla como indique dicha funcin. Esta funcin deber escribir la parte real e imaginaria del complejo en algn formato, utilizando algo como

salida << valor.dameX() << " + " << valor.dameY() << "j";

El operador devuelve un ostream, que ser un return cout. De esta forma se pueden encadenar las llamadas a cout de la forma habitual.

cout << a << " + " << b << endl;

Primero se evala operator << (cout, a), que escribe a en pantalla y devuelve un cout, con lo que la expresin anterior quedara, despus de evaluar esto

cout << " + " << b << endl;

y as consecutivamente.

Hay que tener en cuenta que estos operadores globales no son de la clase, as que slo pueden acceder a mtodos y atributos pblicos de la misma.

El operador cast
Un operador interesante es el operador "cast". En C++, si tenemos dos tipos bsicos distintos, podemos pasar de uno a otro haciendo un cast (siempre que sean compatibles de alguna forma). Por ejemplo

int a; double b;

a = (int)b;

El cast consiste en poner delante, entre parntesis, el tipo que queramos que sea. En algunos casos, como en el de este ejemplo, el cast se hace automticamente y no es necesario ponerlo. Puede que de un "warning" en el compilador avisando de que perderemos los decimales.

En principio, con las clases no se puede hacer cast a otros tipos, pero es posible declarar operadores que lo hagan. La sintaxis sera:

class ComplejoC { public: // Permite hacer un cast de ComplejoC a double operator double (); }

Con este podemos hacer cast de nuestra clase a un double . Es nuestro problema decidir cmo se hace ese cast. En el cdigo de ejemplo que hay ms abajo se ha definido como la operacin mdulo del nmero complejo.

double a; ComplejoC b;

a = (double)b;

En el operator cast se pone operator seguido del tipo al que se quiere hacer el cast. No se pone el tipo del valor devuelto, puesto que ya est claro. Si ponemos operator double, hay que devolver un double .

En el operator cast no se pone parmetro, puesto que el parmetro recibido ser una instancia de la clase.

Conviene tener cuidado con definir muchos operadores cast, puesto que el compilador los tendr todos presentes y ser capaz, encadenando unos con otros, de hacer cast entre tipos que no tienen nada que ver. Por ejemplo, si sumamos un ComplejoC con un DibujoC (que no tienen nada que ver) y ambos tienen cast e int, es posible que el compilador los transforme ambos en int y luego los sume como enteros.

Cmo hacemos un cast al revs?. Es decir, Cmo podemos convertir un double a ComplejoC?. El asunto es sencillo, basta hacer un constructor que admite un double como parmetro.

class ComplejoC { public: ComplejoC (double valor); };

Este constructor sirve para lo que ya sabemos

ComplejoC a(3.0);

o podemos usarlo para hacer un cast de double a ComplejoC

ComplejoC a;

a = (ComplejoC)3.0;

El operador igual
El operator = es como los dems. Simplemente un pequeo detalle. C++ por defecto tiene el operador igual definido para clases del mismo tipo. Por ejemplo, sin necesidad de redefinir nada, podemos hacer

ComplejoC a; ComplejoC b;

a = b;

Este igual por defecto lo nico que hace es copiar el contenido del uno sobre el otro, como si fueran bytes, sin saber qu atributos est copiando ni qu significan. Para clases sencillas, que solo tienen atributos que no son punteros, esto es ms que suficiente.

Si embargo, si algn atributo es un puntero, tenemos que tener mucho cuidado con lo que hacemos. Supongamos que ClaseC tiene un atributo Atributo que es un puntero. Supongamos tambin que en el constructor de la clase, se hace new del puntero para que tenga algo y en el destructor se hace el delete correspondiente.

ClaseC {

public: // Se crea un array de tres enteros ClaseC () { Atributo = new int[3]; }

// Se libera el array. ~ClaseC () { delete [] Atributo; }

protected: int *Atributo; };

Si ahora hacemos esto

// a tiene ahora un array de 3 enteros en su interior ClaseC *a = new ClaseC();

// b tiena ahora otro array de 3 enteros en su interior ClaseC *b = new ClaseC();

/* Se copia el Atributo de b sobre el de a, es decir, ahora a->Atributo apunta al mismo sitio que b->Atributo */ *a = *b;

// Ahora si que la hemos liado. delete b;

Cuando hacemos a=b, con el operador igual por defecto de C++, se hace que el puntero Atributo de a apunte al mismo sitio que el de b. El array original de a->Atributo lo hemos perdido, sigue ocupando memoria y no tenemos ningn puntero a l para liberarlo.

Cuando hacemos delete b, el destructor de b se encarga de liberar su array. Sin embargo, al puntero a->Atributo nadie le avisa de esta liberacin, se queda apuntando a una zona de memoria que ya no es vlida. Cuando intentemos usar a->Atributo ms adelante, puede pasar cualquier cosa (cambios aleatorios de variables, caidas del programa, etc).

En el tema de punteros tienes un poco ms detallado todo esto. All se habla de estructuras, pero tambin se aplica a clases.

La forma de solucionar esto, es definiendo nosotros un operator = que haga una copia real del array, liberando previamente el nuestro o copiando encima los datos.

ClaseC { public: ClaseC &operator = (const ClaseC &original) { int i; /* Damos por supuesto que ambos arrays existen y son de tamao 3 */ for (i=0;i<3;i++) Atributo[i] = original.Atributo[i]; } };

Sobrecarga del operador new y delete


Otro operador interesante de sobrecargar es el new y el delete. Si los sobrecargamos dentro de la clase, cada vez que hagamos un new a nuestra clase se llamar a nuestro operador.

Ms interesante es la sobrecarga de los operadores new y delete globales. Sobrecargando estos operadores se llamar a nuestras funciones cada vez que hagamos un new o un delete de cualquier cosa (clases o variables). Esta caracterstica nos permite hacer contabilidad de punteros, para ver si liberamos todo lo que reservamos o liberamos lo mismo ms veces de la cuenta.

Вам также может понравиться