Sobrecarga del operador de indexación []

El operador [] se usa para acceder a valores de objetos de una determinada clase como si se tratase de arrays. Los índices no tienen por qué ser de un tipo entero o enumerado, cuando se sobrecarga este operador no existe esa limitación.

Donde más útil resulta este operador es cuando se usa con estructuras dinámicas de datos: listas y árboles. Pero también puede servirnos para crear arrays asociativos, donde los índices sean por ejemplo, palabras.

De nuevo explicaremos el uso de este operador usando un ejemplo.

Supongamos que hacemos una clase para hacer un histograma de los valores de rand()/RAND_MAX, entre los márgenes de 0 a 0.0009, de 0.001 a 0.009, de 0.01 a 0.09 y de 0.1 a 1.

Nota: Un histograma es un gráfico o una tabla utilizado en la representación de distribuciones de frecuencias de cualquier tipo de información o función. La clase de nuestro ejemplo podría usar los valores de la tabla para generar ese gráfico.

#include <iostream>
using namespace std;

class Cuenta {
  public:
   Cuenta() { for(int i = 0; i < 4; contador[i++] = 0); }
   int &operator[](double n); // (1)
   
   void Mostrar() const;
   
  private:
   int contador[4];  
};

int &Cuenta::operator[](double n) { // (2)
   if(n < 0.001) return contador[0];
   else if(n < 0.01) return contador[1];
   else if(n < 0.1) return contador[2];
   else return contador[3];
}

void Cuenta::Mostrar() const { 
   cout << "Entre      0 y 0.0009: " << contador[0] << endl; 
   cout << "Entre 0.0010 y 0.0099: " << contador[1] << endl; 
   cout << "Entre 0.0100 y 0.0999: " << contador[2] << endl; 
   cout << "Entre 0.1000 y 1.0000: " << contador[3] << endl; 
}
 
int main() {
   Cuenta C;
   
   for(int i = 0; i < 50000; i++) 
      C[(double)rand()/RAND_MAX]++; // (3)
   C.Mostrar();
   
   return 0;
}

Ejecutar este código en codepad.

En este ejemplo hemos usado un valor double como índice, pero igualmente podríamos haber usado una cadena o cualquier objeto que hubiésemos querido.

El tipo del valor de retorno de operador debe ser el del objeto que devuelve (1). En nuestro caso, al tratarse de un contador, devolvemos un entero. Bueno, en realidad devolvemos una referencia a un entero, de este modo podemos aplicarle el operador de incremento al valor de retorno (3).

En la definición del operador (2), hacemos un tratamiento del parámetro que usamos como índice para adaptarlo al tipo de almacenamiento que usamos en nuestra clase.

Cuando se combina el operador de indexación con estructuras dinámicas de datos como las listas, se puede trabajar con ellas como si se tratada de arrays de objetos, esto nos dará una gran potencia y claridad en el código de nuestros programas.

Sobrecarga del operador de llamada ()

El operador () funciona exactamente igual que el operador [], aunque admite más parámetros.

Este operador permite usar un objeto de la clase para el que está definido como si fuera una función.

Como ejemplo añadiremos un operador de llamada a función que admita dos parámetros de tipo double y que devuelva el mayor contador de los asociados a cada uno de los parámetros.

class Cuenta {
...
   int operator()(double n, double m);
...
};
 
int Cuenta::operator()(double n, double m) {
   int i, j;
   
   if(n < 0.001) i = 0;
   else if(n < 0.01) i = 1;
   else if(n < 0.1) i = 2;
   else i = 3;

   if(m < 0.001) j = 0;
   else if(m < 0.01) j = 1;
   else if(m < 0.1) j = 2;
   else j = 3;
   
   if(contador[i] > contador[j]) return contador[i]; 
   else return contador[j];
}
...

cout << C(0.0034, 0.23) << endl;
...

Por supuesto, el número de parámetros, al igual que el tipo de retorno de la función depende de la decisión del programador.

Comentarios de los usuarios (3)

Daniel
2015-03-21 17:00:08

No entiendo por que en esta parte del programa usa double entre parentesis:

int main() {

Cuenta C;

for(int i = 0; i < 50000; i++)

C[(double)rand()/RAND_MAX]++; // (3)

C.Mostrar();

return 0;

}

si estoy usando el operador de indexacion, deberia de usar un double, pero no tengo que decir que es double, ya estoy en main, no tengo que nombrar nada...

Gracias y un saludo.

Daniel
2015-03-21 17:04:01

¿Podria ser para que la funcion srand me genere un valor double?

Gracias.

Steven R. Davidson
2015-03-21 17:40:09

Hola Daniel,

Estamos realizando un "cásting" (cambio de tipo) al valor retornado por 'rand()', que es un entero. Hacemos esto porque de lo contrario, la división se realiza entre dos valores enteros y por tanto el resultado es un cociente de tipo entero. Esto no es lo que nos interesa, porque queremos un cociente con decimales. Para obligar una división entre valores de tipo 'double', realizamos el cásting a uno de los operandos; podríamos haber elegido la constante simbólica 'RAND_MAX' en lugar del valor retornado por 'rand()'.

Espero haber aclarado la duda.

Steven