Menu
Coddy logo textTech

Перегрузка операторов

Часть раздела Объектно-ориентированное программирование путешествия по 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, и по крайней мере один параметр должен иметь содержащий тип. Вы можете перегружать арифметические операторы (+, -, *, /), операторы сравнения (==, !=, <, >) и унарные операторы (-, !, ++).

Обратите внимание, что операторы сравнения необходимо перегружать парами: если вы определяете ==, необходимо также определить !=.

Используй operator overloading, когда это делает твой код более интуитивным, особенно для математических типов, таких как векторы, комплексные числа или деньги. Избегай его, если смысл операции не очевиден сразу.

challenge icon

Задание

Легко

Давайте создадим class Fraction, который сделает работу с дробями естественной благодаря перегрузке operator. Вместо вызова таких method, как fraction1.Add(fraction2), вы сможете писать интуитивное выражение fraction1 + fraction2.

Вы организуете свой код в двух файлах:

  • Fraction.cs: Создайте class Fraction в namespace Math, представляющий дробь с числителем и знаменателем. Ваш fraction должен иметь:
    • Два доступных только для чтения свойства типа integer: Numerator и Denominator
    • constructor, который accepts числитель и знаменатель (именно в таком порядке)
    • Перегруженный + operator, который складывает две дроби по формуле: (a/b) + (c/d) = (a*d + c*b) / (b*d)
    • Перегруженный * operator, который перемножает две дроби: (a/b) * (c/d) = (a*c) / (b*d)
    • Перегруженный == operator, который возвращает true, если две дроби равны (для сравнения выполните cross multiplication: a*d == c*b)
    • Перегруженный != operator (требуется при перегрузке ==), который возвращает противоположный результат ==
    • method GetDisplay(), который возвращает fraction в виде строки в формате "{Numerator}/{Denominator}"
  • Program.cs: В вашем основном файле создайте две дроби, используя значения input. Продемонстрируйте работу перегруженных operator, сложив и перемножив дроби, а также проверив, равны ли они. Выведите результаты, чтобы показать естественную работу ваших operator.

Вы получите четыре значения input:

  • Числитель первой дроби (целое число)
  • Знаменатель первой дроби (целое число)
  • Числитель второй дроби (целое число)
  • Знаменатель второй дроби (целое число)

Выведите output в следующем формате:

Fraction 1: {GetDisplay()}
Fraction 2: {GetDisplay()}
Sum: {GetDisplay()}
Product: {GetDisplay()}
Are equal: {True/False}

Например, если input имеют значения 1, 2, 2 и 4, output должен быть следующим:

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. Сумма и произведение вычисляются без упрощения — для этого challenge это нормально. Вся прелесть в том, насколько естественно теперь можно работать с дробями, используя привычные operator!

Попробуйте сами

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: Вывести результат в требуемом формате:
        // Дробь 1: {GetDisplay()}
        // Дробь 2: {GetDisplay()}
        // Сумма: {GetDisplay()}
        // Произведение: {GetDisplay()}
        // Are equal: {True/False}
    }
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор C#