Cómo definir operadores para clases propias en c++

Última modificación el Jueves, 30 abril 2009 10:36 Autor: ProgramadorWeb Miércoles, 20 agosto 2008 10:34

Cómo definir operadores para clases propias en c++

Una de las cualidades más interesantes del lenguaje C++, sintácticamente hablando, es la posibilidad de definir operadores para las clases propias. Esto simplifica el uso de dichas clases al reducir el número de métodos a los que hay que invocar para realizar las tareas. Siempre es más sencillo disponer el operador ++ detrás del nombre de un objeto que tener que llamar a un hipotético método Incrementa(), o usar el operador estándar de inserción, <<, para añadir un elemento que llamar a un método Anade().


La definición de un operador en una cierta clase no se diferencia demasiado de la de cualquier método, contando con un valor de retorno y unos parámetros. La distinción es que, en lugar de facilitar un identificador propio, usaremos la palabra operator seguida del operador a definir. El fragmento siguiente, por ejemplo, podría ser la definición del operador + para una hipotética clase Unidad.


long operator+(Unidad& OtraUnidad);


No todos los operadores pueden ser redefinidos, pero sí la mayor parte de ellos: aritméticos, incremento y decremento, inserción y extracción, corchetes e, incluso, los operadores new y delete, lo cual facilitaría el control de la creación y destrucción de objetos de la clase.


Una posibilidad muy interesante, especialmente cuando se trabaja con clases que contienen o representan listas de elementos, es la de poder redefinir el operador [], facilitando así el acceso a los elementos en lugar de implementar métodos como LeeElemento() y AsignaElemento(). Suponga que cuenta con una clase, llamémosla Unidad, que serviría para realizar diversas operaciones sobre las unidades de almacenamiento que hay en el sistema. En principio esta clase podría ser así de sencilla:


// Clase que ofrece datos de unidades


class Unidad {


private:


// Camino raíz de la unidad “X:”


AnsiString Camino;


protected:


// El constructor está protegido


Unidad(char Letra) :


Camino(Letra) { Camino += “:\”; }


// sólo la clase Unidades podrá usarlo


friend class Unidades;


public:


// Métodos públicos


long EspacioTotal();


long EspacioLibre();


};


Como se aprecia, el único constructor disponible es protegido, lo cual significa que no habrá manera de crear directamente un objeto de esta clase. La declaración friend class Unidades, sin embargo, indica que otra clase, llamada Unidades, sí tiene acceso a todos los miembros de ésta. ¿Cómo permitiría esa clase obtener un objeto Unidad asociado a una determinada unidad física de almacenamiento? Podríamos definir un método para ello, pero resultaría más sencillo usar un operador, como se hace aquí:


// Esta clase ofrece una lista de


// unidades y crea objetos Unidad


class Unidades {


public:


// Operador [] que acepta como


// índice la letra de unidad


Unidad* operator[](char Letra)


// crea un objeto Unidad y


// lo devuelve


{ return new Unidad(Letra); }


// Este método crea una lista


// con las letras de unidad


static AnsiString ListaUnidades();


};


A partir de este momento podríamos obtener objetos Unidad usando expresiones como las del fragmento de código siguiente:


Unidades varUnidades;


Unidad * UnaUnidad;


UnaUnidad = varUnidades['C'];


ShowMessage(


UnaUnidad->EspacioLibre());


ShowMessage(


varUnidades.ListaUnidades());


ShowMessage(


varUnidades['G']->EspacioTotal());


La sintaxis varUnidades['C'] resulta bastante más intuitiva que si hubiésemos definido un método y tuviésemos que escribir algo como varUnidades.Unidades(‘C’), no cabe duda. Para obtener realmente algún funcionamiento útil sería preciso finalizar la implementación de las clases Unidad y Unidades, implementación que bien podría ser la mostrada en el Listado 2.


************************** OJO LISTADO ***********************


long Unidad::EspacioTotal()


{


// Variables para recuperar datos


unsigned long // de la unidad


SectoresCluster, BytesSector,


ClustersLibres, ClustersTotales;


// Obtenemos esos datos


GetDiskFreeSpace(


Camino.c_str(), &SectoresCluster,


&BytesSector, &ClustersLibres,


&ClustersTotales);


// y devolvemos el espacio Total en Ks


return SectoresCluster * BytesSector *


ClustersTotales / 1024;


}


long Unidad::EspacioLibre()


{


// Variables para recuperar datos


unsigned long // de la unidad


SectoresCluster, BytesSector,


ClustersLibres, ClustersTotales;


// Obtenemos esos datos


GetDiskFreeSpace(


Camino.c_str(), &SectoresCluster,


&BytesSector, &ClustersLibres,


&ClustersTotales);


// y devolvemos el espacio libre en Ks


return SectoresCluster * BytesSector *


ClustersLibres / 1024;


}


// Este método crea una lista de unidades


// y la devuelve como cadena


AnsiString Unidades::ListaUnidades()


{


char CadenaUnidades[MAX_PATH];


AnsiString Resultado = “”;


int IndiceOrigen = 0;


// Obtenemos la cadena con unidades


GetLogicalDriveStrings(MAX_PATH,


CadenaUnidades);


// Recorremos la cadena hasta


// encontrar un doble nulo


while(CadenaUnidades[IndiceOrigen]) {


// tomamos la letra de unidad


Resultado += CadenaUnidades[IndiceOrigen];


// y si no es la última


if(CadenaUnidades[IndiceOrigen+4])


Resultado += ‘,’; // añadimos separador


// pasamos al siguiente elemento


IndiceOrigen += 4;


}


// Devolvemos la lista


return Resultado;


}


Listado 2. Implementación de los métodos de las clases Unidad y Unidades.



86

Francisco Chartees profesor de informática y autor de diferentes libros sobre lenguajes y sistemas de información.



Montaje del PC


Noé Soriano


noe@idg.es


¿La forma de ensamblar un ordenador personal puede afectar a su rendimiento? Esto, que a primera vista parece absurdo, tiene mucha importancia. A continuación vamos a dar unos sencillos consejos de montaje de algunos de los elementos del hardware de un equipo informático, que pueden aumentar el rendimiento del mismo y reducir algunos errores de funcionamiento. Los lectores escépticos que piensen que las recomendaciones de montaje no influyen en el funcionamiento de un dispositivo electrónico podrán comprobar la utilidad de seguir estos sencillos consejos, aunque la mayoría nada tiene que ver con la mejora de los procesos electrónicos internos que se producen en un equipo informático. Hay que recordar que un ordenador personal no es un dispositivo enteramente electrónico, dispone de partes mecánicas y procesos analógicos que pueden reducir su nivel de errores siguiendo estas sencillas recomendaciones.




Si te ha parecido interesante únete a nuestra comunidad de FACEBOOK y compartelo con tus amigos.





Articulos relacionados:


No olvides compartir Cómo definir operadores para clases propias en c++ en tus redes sociales :-)
     

1 Comentario

  1. ana   |  Martes, 30 junio 2009 a 3:00 pm

    grande…. muchas gracias

Enviar comentario