73 - Sobrecarga de operadores


La sobrecarga de operadores en C# permite redefinir la acción de un operador en relación a una clase.
Por ejemplo podemos plantear una clase Vector y luego redefinir el operador + para dicha clase. Luego cuando sumamos dos objetos de esa clase vector podemos generar otro objeto de dicha clase que resulte de la suma de sus componentes.

El empleo de la sobrecarga de operadores debe hacerse con mucho cuidado de no desvirtuar el concepto que representa dicho operador (por ejemplo sobrecargar el operador "-" para la clase Vector y que genere la suma de sus componentes)

Problema 1:

Plantear una clase VectorEnteros que permita crear un vector de 5 elementos y sobrecargue el operador +

Programa:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SobrecargaOperadores1
{
    class VectorEnteros
    {
        private int []vec;

        public VectorEnteros()
        {
            vec = new int[5];
        }

        public void Cargar()
        {
            for (int f = 0; f < vec.Length; f++)
            {
                Console.Write("Ingrese componente:");
                vec[f] = int.Parse(Console.ReadLine());
            }
        }

        public void Imprimir()
        {
            for (int f = 0; f < vec.Length; f++)
            {
                Console.Write(vec[f] + " ");
            }
            Console.WriteLine();
        }

        public static VectorEnteros operator +(VectorEnteros v1, VectorEnteros v2)
        {
            VectorEnteros su = new VectorEnteros();
            for (int f = 0; f < su.vec.Length; f++)
            {
                su.vec[f] = v1.vec[f] + v2.vec[f];
            }
            return su;
        }

    }
    class Program
    {
        static void Main(string[] args)
        {
            VectorEnteros v1 = new VectorEnteros();
            Console.WriteLine("Carga del primer vector");
            v1.Cargar();
            VectorEnteros v2 = new VectorEnteros();
            Console.WriteLine("Carga del segundo vector");
            v2.Cargar();
            Console.WriteLine("Primer Vector");
            v1.Imprimir();
            Console.WriteLine("Segundo Vector");
            v2.Imprimir();
            VectorEnteros vt;
            vt = v1 + v2;
            Console.WriteLine("Vector Resultante");
            vt.Imprimir();
            Console.ReadKey();
        }
    }
}

La sintaxis para sobrecargar un operador binario es:

public static {valor que retorna} operator {operador}(tipo-parametro nombre, tipo-parametro nombre)

En nuestro ejemplo el tipo de dato que retorna es un objeto de la clase VectorEnteros. El operador que estamos sobrecargando es el "+" y entre paréntesis indicamos los dos parámetros que llegan que son objetos de la clase VectorEnteros:

        public static VectorEnteros operator +(VectorEnteros v1, VectorEnteros v2)

Dentro del método creamos un objeto de la clase VectorEnteros:

            VectorEnteros su = new VectorEnteros();

Luego mediante un for cargamos cada elemento del vector de enteros con los datos de las componentes homólogas de los otros dos vectores:

            for (int f = 0; f < su.vec.Length; f++)
            {
                su.vec[f] = v1.vec[f] + v2.vec[f];
            }

Como estamos en la clase VectorEnteros podemos acceder a los atributos privados vec.

Finalmente retornamos el objeto de la clase VectorEnteros que acabamos de crear:

            return su;

El método completo queda codificado entonces con la siguiente sintaxis:

        public static VectorEnteros operator +(VectorEnteros v1, VectorEnteros v2)
        {
            VectorEnteros su = new VectorEnteros();
            for (int f = 0; f < su.vec.Length; f++)
            {
                su.vec[f] = v1.vec[f] + v2.vec[f];
            }
            return su;
        }

Luego cuando utilizamos el operador + con dos objetos de la clase VectorEnteros el resultado el otro objeto de la clase VectorEnteros:


            VectorEnteros vt;
            vt = v1 + v2;
            Console.WriteLine("Vector Resultante");
            vt.Imprimir();

Como podemos ver no creamos el objeto vt sino la llamada al operador + con dos objetos de la clase VectorEnteros retorna un objeto de la clase VectorEnteros.

Problema 2:

Plantear una clase VectorEnteros que permita crear un vector de 5 elementos y sobrecargue el operador * de un objeto de la clase VectorEnteros con un valor de tipo int (el resultado debe ser otro objeto de la clase VectorEnteros donde cada componente se obtiene de multiplicar su valor por el valor entero)

Programa:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SobrecargaOperadores2
{
    class VectorEnteros
    {
        private int[] vec;

        public VectorEnteros()
        {
            vec = new int[5];
        }

        public void Cargar()
        {
            for (int f = 0; f < vec.Length; f++)
            {
                Console.Write("Ingrese componente:");
                vec[f] = int.Parse(Console.ReadLine());
            }
        }

        public void Imprimir()
        {
            for (int f = 0; f < vec.Length; f++)
            {
                Console.Write(vec[f] + " ");
            }
            Console.WriteLine();
        }

        public static VectorEnteros operator *(VectorEnteros v1, int valor)
        {
            VectorEnteros resu = new VectorEnteros();
            for (int f = 0; f < resu.vec.Length; f++)
            {
                resu.vec[f] = v1.vec[f] * valor;
            }
            return resu;
        }

    }
    class Program
    {
        static void Main(string[] args)
        {
            VectorEnteros v1 = new VectorEnteros();
            Console.WriteLine("Carga del vector");
            v1.Cargar();
            VectorEnteros vr;
            Console.WriteLine("Primer Vector");
            v1.Imprimir();
            vr = v1 * 10;
            Console.WriteLine("Vector resultante");
            vr.Imprimir();
            Console.ReadKey();
        }
    }    
}

Como vemos ahora estamos sobrecargando el operador "*". El método tiene dos parámetros uno de tipo VectorEnteros y otro de tipo int:

        public static VectorEnteros operator *(VectorEnteros v1, int valor)
        {
            VectorEnteros resu = new VectorEnteros();
            for (int f = 0; f < resu.vec.Length; f++)
            {
                resu.vec[f] = v1.vec[f] * valor;
            }
            return resu;
        }

No lo hemos hecho pero podríamos también sobrecargar el operador "*" y recibir como parámetro dos objetos de la clase VectorEnteros:


        public static VectorEnteros operator *(VectorEnteros v1, VectorEnteros v2)
        {
            VectorEnteros resu = new VectorEnteros();
            for (int f = 0; f < resu.vec.Length; f++)
            {
                resu.vec[f] = v1.vec[f] * v2.vec[f];
            }
            return resu;
        }

Operación unaria

Los ejemplos anteriores mostraban la sobrecarga de operadores binarios (un operador y dos operandos), un operador unario afecta solo un operado.

Problema 3:

Sobrecargar el operador ++ en la clase VectorEnteros (se debe incrementar en uno cada elemento)

Programa:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SobrecargaOperadores3
{
    class VectorEnteros
    {
        private int[] vec;

        public VectorEnteros()
        {
            vec = new int[5];
        }

        public void Cargar()
        {
            for (int f = 0; f < vec.Length; f++)
            {
                Console.Write("Ingrese componente:");
                vec[f] = int.Parse(Console.ReadLine());
            }
        }

        public void Imprimir()
        {
            for (int f = 0; f < vec.Length; f++)
            {
                Console.Write(vec[f] + " ");
            }
            Console.WriteLine();
        }

        public static VectorEnteros operator ++(VectorEnteros v)
        {
            VectorEnteros resu = new VectorEnteros();
            for (int f = 0; f < v.vec.Length; f++)
            {
                resu.vec[f]=v.vec[f]+1;
            }
            return resu;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            VectorEnteros v1 = new VectorEnteros();
            Console.WriteLine("Carga del vector");
            v1.Cargar();
            Console.WriteLine("Impresión del vector");
            v1.Imprimir();
            v1++;
            Console.WriteLine("Impresión del vector luego del operador ++");
            v1.Imprimir();
            Console.ReadKey();
        }
    }
}

Cuando se sobrecarga un operador unario tenemos un solo parámetro:

        public static VectorEnteros operator ++(VectorEnteros v)
        {
            VectorEnteros resu = new VectorEnteros();
            for (int f = 0; f < v.vec.Length; f++)
            {
                resu.vec[f]=v.vec[f]+1;
            }
            return resu;
        }

Para ejecutar el operador luego desde la Main:


            VectorEnteros v1 = new VectorEnteros();
            Console.WriteLine("Carga del vector");
            v1.Cargar();
            Console.WriteLine("Impresión del vector");
            v1.Imprimir();
            v1++;

Sobrecarga de operadores relacionales.

Los operadores relacionales devuelven un valor de tipo bool.

Cuando se sobrecargan los operadores relacionales estamos obligados a implementar en pares, es decir si implementamos el == debemos implementar el != en forma obligatoria (sino se genera un error sintáctico).

Los pares son:

  • ==
    !=
  • <
    >
  • <=
    >=

Problema 4:

Sobrecargar el operador == en la clase VectorEnteros (retornar true si los cinco enteros son iguales)

Programa:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SobrecargaOperadores4
{
    class VectorEnteros
    {
        private int[] vec;

        public VectorEnteros()
        {
            vec = new int[5];
        }

        public void Cargar()
        {
            for (int f = 0; f < vec.Length; f++)
            {
                Console.Write("Ingrese componente:");
                vec[f] = int.Parse(Console.ReadLine());
            }
        }

        public void Imprimir()
        {
            for (int f = 0; f < vec.Length; f++)
            {
                Console.Write(vec[f] + " ");
            }
            Console.WriteLine();
        }

        public static bool operator ==(VectorEnteros v1, VectorEnteros v2)
        {
            for (int f = 0; f < v1.vec.Length; f++)
            {
                if (v1.vec[f] != v2.vec[f])
                    return false;
            }
            return true;
        }

        public static bool operator !=(VectorEnteros v1, VectorEnteros v2)
        {
            for (int f = 0; f < v1.vec.Length; f++)
            {
                if (v1.vec[f] == v2.vec[f])
                    return false;
            }
            return true;
        }

    }

    class Program
    {
        static void Main(string[] args)
        {
            VectorEnteros v1 = new VectorEnteros();
            Console.WriteLine("Carga del primer vector");
            v1.Cargar();
            VectorEnteros v2 = new VectorEnteros();
            Console.WriteLine("Carga del segundo vector");
            v2.Cargar();
            if (v1 == v2)
                Console.Write("Todos los elementos son iguales");
            else
                Console.Write("No todos los elementos son iguales");
            Console.ReadKey();
        }
    }
}

Retornar