Перегрузка операторов
Часть раздела Объектно-ориентированное программирование путешествия по C# на Coddy — урок 36 из 70.
Перегрузка операторов позволяет вам определить, как такие операторы, как +, - или ==, ведут себя с вашими пользовательскими классами. Вместо вызова таких методов, как point1.Add(point2), вы можете написать более естественное point1 + point2.
Чтобы перегрузить оператор, вы создаете специальный статический метод, используя ключевое слово 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);
}
}Теперь вы можете складывать векторы естественным образом:
Vector v1 = new Vector(3, 4);
Vector v2 = new Vector(1, 2);
Vector v3 = v1 + v2; // X = 4, Y = 6Метод должен быть public static, и как минимум один параметр должен быть содержащим типом. Вы можете перегружать арифметические операторы (+, -, *, /), операторы сравнения (==, !=, <, >) и унарные операторы (-, !, ++).
Обратите внимание, что операторы сравнения должны быть перегружены парами — если вы определяете ==, вы также должны определить !=.
Используйте перегрузку операторов, когда это делает ваш код более интуитивно понятным, особенно для математических типов, таких как векторы, комплексные числа или денежные суммы. Избегайте её, когда значение операции не является очевидным сразу.
Задание
ЛегкоДавайте создадим класс Fraction, который сделает работу с дробями естественной благодаря перегрузке операторов. Вместо вызова методов вроде fraction1.Add(fraction2), вы сможете писать интуитивно понятное fraction1 + fraction2.
Вы организуете свой код в двух файлах:
Fraction.cs: Создайте классFractionв пространстве именMath, который представляет дробь с числителем и знаменателем. Ваша дробь должна иметь:- Два целочисленных свойства только для чтения:
NumeratorиDenominator - Конструктор, который принимает числитель и знаменатель (именно в таком порядке)
- Перегруженный оператор
+, который складывает две дроби по формуле:(a/b) + (c/d) = (a*d + c*b) / (b*d) - Перегруженный оператор
*, который перемножает две дроби:(a/b) * (c/d) = (a*c) / (b*d) - Перегруженный оператор
==, который возвращаетtrue, если две дроби равны (используйте перекрестное умножение для сравнения:a*d == c*b) - Перегруженный оператор
!=(требуется при перегрузке==), который возвращает значение, противоположное== - Метод
GetDisplay(), который возвращает дробь в виде строки в формате"{Numerator}/{Denominator}"
- Два целочисленных свойства только для чтения:
Program.cs: В основном файле создайте две дроби, используя входные значения. Продемонстрируйте работу перегруженных операторов, сложив их, перемножив и проверив на равенство. Выведите результаты, чтобы показать естественную работу ваших операторов.
Вы получите четыре входных значения:
- Числитель первой дроби (целое число)
- Знаменатель первой дроби (целое число)
- Числитель второй дроби (целое число)
- Знаменатель второй дроби (целое число)
Выведите результат в следующем формате:
Fraction 1: {GetDisplay()}
Fraction 2: {GetDisplay()}
Sum: {GetDisplay()}
Product: {GetDisplay()}
Are equal: {True/False}Например, если входные данные 1, 2, 2 и 4, вывод должен быть следующим:
Fraction 1: 1/2
Fraction 2: 2/4
Sum: 8/8
Product: 2/8
Are equal: TrueОбратите внимание, что 1/2 и 2/4 признаются равными, так как 1*4 == 2*2. Сумма и произведение вычисляются без упрощения — для этой задачи это нормально. Прелесть в том, насколько естественно теперь можно работать с дробями, используя привычные операторы!
Шпаргалка
Перегрузка операторов позволяет определять пользовательское поведение для таких операторов, как +, -, *, ==, при работе с вашими классами.
Чтобы перегрузить оператор, создайте метод public static, используя ключевое слово 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);
}
}Использование:
Vector v1 = new Vector(3, 4);
Vector v2 = new Vector(1, 2);
Vector v3 = v1 + v2; // X = 4, Y = 6Вы можете перегружать:
- Арифметические операторы:
+,-,*,/ - Операторы сравнения:
==,!=,<,>(должны перегружаться парами) - Унарные операторы:
-,!,++
При перегрузке == вы также должны перегрузить !=:
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);
}Попробуйте сами
using System;
using Math;
class Program
{
public static void Main(string[] args)
{
// Считать входные данные для первой дроби
int num1 = Convert.ToInt32(Console.ReadLine());
int den1 = Convert.ToInt32(Console.ReadLine());
// Считать входные данные для второй дроби
int num2 = Convert.ToInt32(Console.ReadLine());
int den2 = Convert.ToInt32(Console.ReadLine());
// TODO: Создать два объекта Fraction, используя введенные значения
// TODO: Использовать перегруженный оператор +, чтобы сложить дроби
// TODO: Использовать перегруженный оператор *, чтобы перемножить дроби
// TODO: Использовать перегруженный оператор == для проверки равенства
// TODO: Вывести результат в требуемом формате:
// Fraction 1: {GetDisplay()}
// Fraction 2: {GetDisplay()}
// Sum: {GetDisplay()}
// Product: {GetDisplay()}
// Are equal: {True/False}
}
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыПространства имен и директивыВведение в классы и объектыКлючевое слово 'this'Методы и параметрыПоля и свойстваКонструкторыИнициализаторы объектовИтоги — Простой калькулятор4Наследование
Основы синтаксиса наследования (:)Ключевое слово 'base'Ключевые слова Virtual и OverrideЗапечатанные классыБазовый класс 'object'Итоги — Иерархия сотрудников7Продвинутые возможности
Перегрузка операторовИндексаторы (this[])Переопределение ToString()Методы расширенияПовторение — Пользовательский список10Паттерны проектирования. Часть 1
Введение в паттерны проектированияПотокобезопасный SingletonПаттерн FactoryПаттерн Observer (События)Паттерн Strategy13Финальные испытания
Платформа для онлайн-обученияКомпонент игрового персонажаСервис аренды транспорта2Свойства и статические члены
Автоматически реализуемые свойстваСвойства только для чтения и записиСтатические поля и методыСтатические классыЧлены в виде выражений5Полиморфизм и интерфейсы
Полиморфизм: компиляция vs выполнениеИнтерфейс vs абстрактный классМножественные интерфейсыЯвные интерфейсыUpcasting и DowncastingИтоги: Калькулятор фигур8Продвинутые концепции ООП
Композиция вместо наследованияGenerics (классы и методы)Делегаты и событияАтрибуты и рефлексияIDisposable и оператор usingОсновы Dependency Injection11Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн Компоновщик3Архитектура классов
Экземплярные и статические данныеКлючевые слова 'readonly' и 'const'Опорные поляПовторение — Менеджер банковских счетов6Инкапсуляция
Модификаторы доступаСвойства для инкапсуляцииРеализация скрытия данныхПаттерны неизменяемостиИтоги — Записи студентов9Переменное количество аргументов
Ключевое слово 'params'Необязательные параметрыИменованные аргументыПерегрузка методов