Sobrecarga de operadores
Parte de la sección Programación Orientada a Objetos del Journey de C# de Coddy — lección 36 de 70.
La sobrecarga de operadores te permite definir cómo se comportan los operadores como +, - o == con tus clases personalizadas. En lugar de llamar a métodos como point1.Add(point2), puedes escribir el más natural point1 + point2.
Para sobrecargar un operador, se crea un método estático especial utilizando la palabra clave operator:
public class Vector
{
public int X { get; }
public int Y { get; }
public Vector(int x, int y)
{
X = x;
Y = y;
}
public static Vector operator +(Vector a, Vector b)
{
return new Vector(a.X + b.X, a.Y + b.Y);
}
}Ahora puedes sumar vectores de forma natural:
Vector v1 = new Vector(3, 4);
Vector v2 = new Vector(1, 2);
Vector v3 = v1 + v2; // X = 4, Y = 6El método debe ser public static, y al menos un parámetro debe ser el tipo contenedor. Puedes sobrecargar los operadores aritméticos (+, -, *, /), los operadores de comparación (==, !=, <, >) y los operadores unarios (-, !, ++).
Ten en cuenta que los operadores de comparación deben sobrecargarse por pares: si defines ==, también debes definir !=.
Usa la sobrecarga de operadores cuando haga que tu código sea más intuitivo, especialmente para tipos matemáticos como vectores, números complejos o dinero. Evítala cuando el significado de la operación no sea inmediatamente obvio.
Desafío
FácilVamos a construir una clase Fraction que haga que trabajar con fracciones se sienta natural a través de la sobrecarga de operadores. En lugar de llamar a métodos como fraction1.Add(fraction2), podrás escribir el intuitivo fraction1 + fraction2.
Organizarás tu código en dos archivos:
Fraction.cs: Crea una claseFractionen el espacio de nombresMathque represente una fracción con un numerador y un denominador. Tu fracción debe tener:- Dos propiedades de enteros de solo lectura:
NumeratoryDenominator - Un constructor que acepte el numerador y el denominador (en ese orden)
- Un operador
+sobrecargado que sume dos fracciones usando la fórmula:(a/b) + (c/d) = (a*d + c*b) / (b*d) - Un operador
*sobrecargado que multiplique dos fracciones:(a/b) * (c/d) = (a*c) / (b*d) - Un operador
==sobrecargado que devuelvatruesi dos fracciones son iguales (usa la multiplicación cruzada para comparar:a*d == c*b) - Un operador
!=sobrecargado (requerido cuando sobrecargas==) que devuelva lo opuesto de== - Un método
GetDisplay()que devuelva la fracción como una cadena en el formato"{Numerator}/{Denominator}"
- Dos propiedades de enteros de solo lectura:
Program.cs: En tu archivo principal, crea dos fracciones usando valores de entrada. Demuestra los operadores sobrecargados sumándolos, multiplicándolos y comprobando si son iguales. Imprime los resultados para mostrar tus operadores funcionando de manera natural.
Recibirás cuatro entradas:
- Numerador de la primera fracción (entero)
- Denominador de la primera fracción (entero)
- Numerador de la segunda fracción (entero)
- Denominador de la segunda fracción (entero)
Imprime la salida en este formato:
Fraction 1: {GetDisplay()}
Fraction 2: {GetDisplay()}
Sum: {GetDisplay()}
Product: {GetDisplay()}
Are equal: {True/False}Por ejemplo, si las entradas son 1, 2, 2 y 4, la salida debería ser:
Fraction 1: 1/2
Fraction 2: 2/4
Sum: 8/8
Product: 2/8
Are equal: TrueObserva cómo 1/2 y 2/4 son reconocidos como iguales porque 1*4 == 2*2. La suma y el producto se calculan sin simplificación; eso está bien para este desafío. ¡La belleza reside en lo natural que ahora puedes trabajar con fracciones usando operadores familiares!
Hoja de referencia
La sobrecarga de operadores le permite definir un comportamiento personalizado para operadores como +, -, *, == con sus clases.
Para sobrecargar un operador, cree un método public static utilizando la palabra clave operator. Al menos un parámetro debe ser del tipo contenedor:
public class Vector
{
public int X { get; }
public int Y { get; }
public Vector(int x, int y)
{
X = x;
Y = y;
}
public static Vector operator +(Vector a, Vector b)
{
return new Vector(a.X + b.X, a.Y + b.Y);
}
}Uso:
Vector v1 = new Vector(3, 4);
Vector v2 = new Vector(1, 2);
Vector v3 = v1 + v2; // X = 4, Y = 6Puede sobrecargar:
- Operadores aritméticos:
+,-,*,/ - Operadores de comparación:
==,!=, <code><,(deben sobrecargarse en pares) - Operadores unarios:
-,!,++
Al sobrecargar ==, también debe sobrecargar !=:
public static bool operator ==(Vector a, Vector b)
{
return a.X == b.X && a.Y == b.Y;
}
public static bool operator !=(Vector a, Vector b)
{
return !(a == b);
}Pruébalo tú mismo
using System;
using Math;
class Program
{
public static void Main(string[] args)
{
// Leer la entrada para la primera fracción
int num1 = Convert.ToInt32(Console.ReadLine());
int den1 = Convert.ToInt32(Console.ReadLine());
// Leer la entrada para la segunda fracción
int num2 = Convert.ToInt32(Console.ReadLine());
int den2 = Convert.ToInt32(Console.ReadLine());
// TODO: Crear dos objetos Fraction utilizando los valores de entrada
// TODO: Utilizar el operador + sobrecargado para sumar las fracciones
// TODO: Utilizar el operador * sobrecargado para multiplicar las fracciones
// TODO: Utilizar el operador == sobrecargado para comprobar la igualdad
// TODO: Imprimir la salida en el formato requerido:
// Fraction 1: {GetDisplay()}
// Fraction 2: {GetDisplay()}
// Sum: {GetDisplay()}
// Product: {GetDisplay()}
// Are equal: {True/False}
}
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
1Fundamentos de OOP
Archivos externosNamespaces y directivasIntro a clases y objetosLa palabra clave 'this'Métodos y parámetrosCampos vs PropiedadesConstructoresInicializadores de objetosResumen - Calculadora simple4Herencia
Sintaxis básica de herencia (:)La palabra clave 'base'Palabras clave Virtual y OverrideClases selladas (Sealed)La clase base 'object'Resumen: Jerarquía de empleados7Características avanzadas
Sobrecarga de operadoresIndexadores (this[])Sobrescritura de ToString()Métodos de extensiónResumen - Lista personalizada10Patrones de diseño - Parte 1
Introducción a los patrones de diseñoSingleton Thread-SafePatrón FactoryPatrón Observer (Eventos)Patrón Strategy2Propiedades y miembros estáticos
Propiedades autoimplementadasPropiedades de solo lectura y escrituraCampos y métodos estáticosClases estáticasMiembros con cuerpo de expresión5Polimorfismo e Interfaces
Polimorfismo: Compilación vs. EjecuciónInterfaz vs. Clase AbstractaInterfaces MúltiplesInterfaces ExplícitasUpcasting y DowncastingRepaso: Calculadora de Figuras8Conceptos avanzados de POO
Composición sobre herenciaGenéricos (clases y métodos)Delegados y eventosAtributos y ReflexiónIDisposable y la sentencia usingFundamentos de Inyección de dependencias11Patrones de diseño, parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón Composite3Arquitectura de clases
Datos de instancia vs. estáticosPalabras clave 'readonly' y 'const'Campos de respaldoResumen - Gestor de cuentas bancarias6Encapsulamiento
Modificadores de accesoPropiedades para el encapsulamientoImplementación de ocultamiento de datosPatrones de inmutabilidadRepaso - Registros de estudiantes