Anuncios

Bienvenidos sean a este post, hoy veremos una palabra clave muy importante.

Anuncios

Esta palabra nos permite hacer sobrecargas de los operadores. Es decir, podemos cambiar la conducta de los operadores. Veamos como es su sintaxis:

tipo_dato operator simbolo (argumentos) {
	... instrucciones ...
}
Anuncios

Se define igual que una funcion. Primero ira el tipo de dato que devolvemos con la funcion, seguido ira la palabra operator y despues el simbolo del operador a sobrecargar. Los argumentos como en cualquier funcion son opcionales. En el bloque iran todas las instrucciones nuevas que ejecutara el operador. Analicemos el siguiente ejemplo:

#include <iostream>

class Contador
{
public:
        int GetVal() const { return valor; }
        void incrementar() { ++valor; }
        const Contador & operator++ () {
                ++valor;
                return *this;
        }
private:
        int valor;
};

int main()
{
        Contador c;
        c.incrementar();
        for(int i = 0; i < 3; i++)
        {
                std::cout << "Valor c: " << c.GetVal()  << std::endl;
                ++c;
        }
        return 0;
}
Anuncios
Anuncios

Primero definiremos una clase llamada Contador. En la parte privada tendremos una sola propiedad llamada valor. En la parte publica tendremos un metodo llamado GetVal que se encarga de devolver el valor de la propiedad privada. El siguiente metodo llamado incrementar solamente incrementa en uno a valor. Luego tenemos al metodo que realizara la sobrecarga del operador ++. Aqui lo declaramos como constante, esto es opcional pero es una buena practica, en este incrementaremos a valor de manera prefija. Es decir, primero incrementaremos el valor y luego lo usamos. Para finalmente devolver el valor mediante el puntero this. Cada vez que se crea un objeto de una clase, este es basicamente una copia en memoria de la clase. Con las propiedades, metodos y valores asignados a este segmento de memoria. Este puntero nos asegura que siempre trabajaremos con el objeto desde donde se llamo. Por ende, siempre devolveremos el valor modificado del objeto en cuestion.

Anuncios

En el main, primero crearemos un objeto de esta clase y luego llamaremos a incrementar para aumentar a valor de manera inicial. Despues tenemos un bucle donde haremos tres pasadas y en cada pasada mostraremos a valor y luego lo incrementaremos mediante el operador ++ aplicandolo al objeto. Con esto comentado, compilemos y veamos como es la salida:

$ ./oper
Valor c: 1
Valor c: 2
Valor c: 3
$
Anuncios

Esto funciono perfectamente pero que sucede si queremos usar a postfijo, utilizar primero el valor y luego incrementarlo, en lugar de prefijo? Para ello modificaremos el codigo de la siguiente manera:

#include <iostream>

class Contador
{
public:
        int GetVal() const { return valor; }
        void incrementar() { ++valor; }
        const Contador & operator++ ();
        const Contador operator++ (int);
private:
        int valor;
};

const Contador & Contador::operator++() {
        ++valor;
        return *this;
}

const Contador Contador::operator++ (int x) {
        Contador temp(*this);
        ++valor;
        return temp;
}

int main()
{
        Contador c;
        c.incrementar();
        Contador d;
        for(int i = 0; i < 3; i++)
        {
                std::cout << "Valor c: " << c.GetVal() << std::endl;
                ++c;
                std::cout << "Valor d: " << d.GetVal() << std::endl;
                d++;
        }
        return 0;
}
Anuncios
Anuncios

La primera modificacion fue agregar un nuevo metodo para sobrecargar al operador ++ y a esta junto con el metodo anterior los convertimos en prototipos. El nuevo metodo que hara la sobrecarga del operador ++ postfijo recibira un valor de argumento para diferenciarlo con el anterior. La definicion de la sobrecarga anterior sigue siendo la misma. El nuevo metodo primero creara un objeto del tipo de la clase y a este le pasaremos al puntero this para que almacene los datos. Incrementamos a valor y luego devolvemos el objeto anteriormente creado. En el main, las modificaciones que hicimos fue crear un nuevo objeto de la clase. Y en el bucle mostraremos los valores devueltos por GetVal en cada objeto. Al primero lo seguiremos incrementando como prefijo y al nuevo objeto lo incrementaremos como postfijo. Compilemos y veamos como es la salida:

$ ./oper
Valor c: 1
Valor d: 0
Valor c: 2
Valor d: 1
Valor c: 3
Valor d: 2
$
Anuncios

Como pueden ver ahora podemos utilizar al operador ++ tanto para el prefijo y postfijo. Tomemos el codigo anterior y modifiquemoslo de la siguiente manera:

#include <iostream>

class Contador
{
public:
        Contador(): valor(0) {}
        Contador(int inicial): valor(inicial) {}
        int GetVal() const { return valor; }
        void incrementar() { ++valor; }
        const Contador & operator++ ();
        const Contador operator++ (int);
private:
        int valor;
};

const Contador & Contador::operator++() {
        ++valor;
        return *this;
}

const Contador Contador::operator++ (int x) {
        Contador temp(*this);
        ++valor;
        return temp;
}

int main()
{
        Contador valor_1(10), valor_2(5), valor_3;
        valor_3 = valor_1 + valor_2;
        std::cout << valor_3.GetVal() << std::endl;

        return 0;
}
Anuncios
Anuncios

Las modificaciones son pocas y las primeras son en la clase. En esta agregaremos dos constructores. El primero es el predeterminado pero haremos que inicie a valor con 0. El otro se encarga de recibir un valor y lo asigna a la propiedad. Por lo tanto, cada vez que iniciemos una instancia de la clase se establecera un valor inicial. La siguiente modificacion sera en el main. Primero crearemos tres objetos de la clase. Los dos primeros con un valor y el ultimo sin ninguno. Luego sumaremos los dos primeros objetos y lo asignaremos al tercero. Para finalmente mostrar el valor almacenado en el ultimo objeto. Compilemos y veamos que sucede:

$ g++ oper.cpp -o oper
oper.cpp: In function ‘int main()’:
oper.cpp:35:27: error: no match for ‘operator+’ (operand types are ‘Contador’ and ‘Contador’)
   35 |         valor_3 = valor_1 + valor_2;
      |                   ~~~~~~~ ^ ~~~~~~~
      |                   |         |
      |                   Contador  Contador
$
Anuncios

Nos informa que no existe un operador para este tipo de datos. Para poder habilitarlo modificaremos el codigo de la siguiente manera:

#include <iostream>

class Contador
{
public:
        Contador(): valor(0) {}
        Contador(int inicial): valor(inicial) {}
        int GetVal() const { return valor; }
        void incrementar() { ++valor; }
        const Contador & operator++ ();
        const Contador operator++ (int);
        Contador operator+ (const Contador &);
private:
        int valor;
};

const Contador & Contador::operator++() {
        ++valor;
        return *this;
}

const Contador Contador::operator++ (int x) {
        Contador temp(*this);
        ++valor;
        return temp;
}

Contador Contador::operator+ (const Contador & rhs) {
        return Contador(valor + rhs.GetVal());
}

int main()
{
        Contador valor_1(10), valor_2(5), valor_3;
        valor_3 = valor_1 + valor_2;
        std::cout << valor_3.GetVal() << std::endl;

        return 0;
}
Anuncios
Anuncios

Primero agregaremos el prototipo de operator en la clase para el operador +. Este recibira un argumento del tipo de la clase. En la definicion como argumento pasaremos un tipo de dato muy particular denominado como rhs (right hand side). Este representa a todo lo que se encuentra del lado derecho del simbolo, en este caso a +. Por lo tanto, el argumento sera el valor contenido en valor_2. En el bloque devolveremos un objeto de tipo Contador y aqui le pasaremos la suma del valor del objeto mas el recibido como argumento. Si se lo preguntan tambien existe una referencia para el lado izquierdo del simbolo, se denomina como lhs (left hand side). En el main seguimos realizando la misma operacion e intentaremos mostrar el nuevo valor asignado. Compilemos y veamos la salida:

$ ./oper
15
$
Anuncios

Como pueden ver se realizo la operacion correctamente. Esta palabra esta pensada principalmente para lo que realizamos en este post. Dar la posibilidad de poder usar los distintos operadores para los objetos de las clases que utilicemos. Si bien podemos asignar cualquier conducta a los operaddores, por lo general se respeta la conducta del mismo y la idea principal es permitir esa operacion entre los nuevos tipos de datos. Se puede sobrecargar casi todos los operadores pero los unicos que no se pueden son:

  • :: Operador de relacion
  • . Operador de acceso
  • .* Operador de acceso a traves de puntero
  • ?: Operador condicional
Anuncios

En resumen, hoy hemos visto a operator, que es, para que sirve, como se aplica, una serie de ejemplos para aplicar la sobrecarga de varios operadores. Espero les sea de utilidad sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.

Anuncios
pp258

Donatión

It’s for site maintenance, thanks!

$1.50