Урок 8. Перегрузка базовых операторов C#


На восьмом уроке учебника по объектно-ориентированному программированию на языке C# описывается третий метод перегрузки. Перегружая функциональность операторов, можно определить работу стандартных операторов, включая + и - для новых классов.

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

До сих пор на этих уроках мы создали классы для представления объектов реального мира в комплекте с их соответствующими методами и свойствами. Эти объекты не требовали реализации арифметических операторов, так как этот тип функциональности был неуместен. В этой статье мы создадим класс, который поддерживает арифметические операции с помощью перегрузки операторов.

Перегрузка оператора - это просто процесс добавления функциональности оператора в класс. Это позволяет точно определить, как оператор ведет себя при использовании с вашим классом и другими типами данных. Это может быть стандартное использование, такое как возможность добавления значений двух векторов, более сложная математика для умножения матриц или неарифметические функции, такие как использование оператора + для добавления нового элемента в коллекцию или объединения содержимого двух массивов. Несколько перегруженных версий операторов также могут быть созданы для обеспечения различных функциональных возможностей в соответствии с обрабатываемыми типами данных, аналогично различным сигнатурам перегрузки метода.

В этой статье мы создадим новый класс для представления двумерного вектора со свойствами X и Y. Мы будем использовать этот класс в этой статье и будущих статьях, чтобы продемонстрировать перегрузку операторов. Для начала создайте новое консольное приложение с именем "VectorDemo "и добавьте новый файл класса с именем "Vector". Добавьте следующий код в новый класс, чтобы создать свойства и базовый конструктор:

private int _x, _y;
 
public Vector(int x, int y) { _x = x; _y = y; }
 
public int X
{
    get { return _x; }
    set { _x = value; }
}
 
public int Y
{
    get { return _y; }
    set { _y = value; }
}
Перегрузка бинарного оператора

Первый тип рассматриваемого оператора-это двоичный оператор, названный так потому, что для работы с ним требуется два значения. К ним относятся простые арифметические операторы, такие как+, -,*, / и %. Для объявления двоичного оператора используется следующий синтаксис:

public static result-type operator binary-operator (
     op-type operand,
     op-type2 operand2
)
Это первоначально кажется довольно сложным объявлением, но на самом деле довольно просто. Объявление начинается с public static, поскольку все операторы должны быть объявлены как таковые. Другие области не разрешены и не являются нестатическими операторами.

Тип результата определяет тип данных или класс, возвращаемый в результате использования оператора. Обычно это будет тот же тип, что и класс, в котором он определяется. Однако это не обязательно так, и вполне допустимо возвращать данные другого типа.

Ключевое слово operator добавляется, чтобы сообщить компилятору, что следующий символ двоичного оператора является оператором, а не обычным методом. Затем этот оператор обработает два параметра операнда, каждый из которых имеет свой тип данных (op-type и op-type2). По крайней мере один из этих операндов должен быть того же типа, что и содержащий его класс.

Создание оператора сложения ( + )

Синтаксис бинарных операторов теперь можно использовать для создания нового оператора сложения для класса Vector. Этот оператор просто сложит элементы X и Y двух векторов вместе и вернет новый вектор, содержащий результат. Добавьте следующее В класс Vector, чтобы обеспечить эту функциональность. Обратите внимание, что вместо корректировки одного из операндов создается новый вектор. Это связано с тем, что операнды являются ссылочными типами, и в этом случае исходные значения не должны обновляться.

public static Vector operator +(Vector v1, Vector v2)
{
    return new Vector(v1.X + v2.X, v1.Y + v2.Y);
}
Теперь мы можем проверить новый оператор вектора, изменив основной метод программы. Следующая программа создает экземпляры двух векторных объектов, складывает их вместе и выводит значения свойств X и Y результирующего вектора.

static void Main(string[] args)
{
    Vector v1 = new Vector(4, 11);
    Vector v2 = new Vector(0, 8);
 
    Vector v3 = v1 + v2;
 
    Console.WriteLine("({0},{1})", v3.X, v3.Y);     // "(4,19)"
}
Создание оператора вычитания ( -)

Сложение является коммутативной операцией. Это означает, что порядок двух операндов может быть изменен без влияния на результат. В случае вычитания это не так, поэтому важно помнить, что первый операнд в объявлении представляет значение слева от оператора, а второй операнд представляет значение справа. Если они используются неправильно, результирующее значение будет неверным. Используя эти знания, мы можем добавить оператор вычитания к классу векторов:

public static Vector operator -(Vector v1, Vector v2)
{
    return new Vector(v1.X - v2.X, v1.Y - v2.Y);
}
Чтобы протестировать новый оператор, измените метод Main следующим образом и выполните программу.

static void Main(string[] args)
{
    Vector v1 = new Vector(4, 11);
    Vector v2 = new Vector(0, 8);
 
    Vector v3 = v1 - v2;
 
    Console.WriteLine("({0},{1})", v3.X, v3.Y);     // "(4,3)"
}
Создание оператора умножения ( * )

Последний двоичный оператор, который будет добавлен в класс Vector, предназначен для умножения. Этот оператор будет использоваться для масштабирования вектора путем умножения свойств X и Y на одно и то же целочисленное значение. Это демонстрирует использование операндов другого типа для класса, в котором они определены.

public static Vector operator *(Vector v1, int scale)
{
    return new Vector(v1.X * scale, v1.Y * scale);
}
Чтобы проверить оператор умножения, снова настройте основной метод:

static void Main(string[] args)
{
    Vector v1 = new Vector(4, 11);
 
    Vector v2 = v1 * 3;
 
    Console.WriteLine("({0},{1})", v2.X, v2.Y);     // "(12,33)"
}
В коде оператора для оператора умножения вектор является первым операндом, а целое число-вторым. Это означает, что порядок, используемый в операторе умножения, должен иметь вектор слева от оператора и целое значение справа. Изменение порядка операндов в методе Main приведет к ошибке компилятора.

static void Main(string[] args)
{
    Vector v1 = new Vector(4, 11);
 
    Vector v2 = 3 * v1;
 
    Console.WriteLine("({0},{1})", v2.X, v2.Y);    // не компилируется
}
Если класс должен поддерживать оба варианта умножения, оба должны быть объявлены в коде. Это обеспечивает преимущество, позволяя порядок операндов изменить базовую функцию. Чтобы обеспечить второй вариант умножения, добавьте следующий код в класс Vector. После этого программа будет выполнена правильно.

public static Vector operator *(int scale, Vector v1)
{
    return new Vector(v1.X * scale, v1.Y * scale);
}
Составные операторы присваивания

Когда арифметический двоичный оператор объявлен, соответствующий составной оператор присваивания также становится доступным классу. Это можно продемонстрировать, изменив основной метод программы:

Vector v1 = new Vector(4, 11);
 
v1 *= 5;
 
Console.WriteLine("({0},{1})", v1.X, v1.Y);         // "(20,55)"
Перегрузка унарного оператора

Унарные операторы-это те, которые требуют одного операнда. К ним относятся простые операторы инкремента (++) и декремента ( -- ). Для объявления унарного оператора используется следующий синтаксис:

public static result-type operator unary-operator (op-type operand)
Этот синтаксис почти идентичен синтаксису, используемому для бинарных операторов. Разница в том, что объявляется только один операнд. Тип операнда должен совпадать с классом, в котором объявлен оператор.

Создание операторов инкремента и декремента

Используя синтаксис, определенный выше, теперь мы можем добавить операторы инкремента и декремента в класс Vector. Обратите внимание, что для каждого из них существует только одно определение. Невозможно различить префиксную и постфиксную версии оператора, поэтому обе они обеспечивают одинаковую базовую функциональность.

Чтобы объявить эти два оператора, добавьте следующий код в класс Vector. Каждый шаг увеличивает или уменьшает свойства X и Y для векторных объектов.

public static Vector operator ++(Vector v)
{
    v.X++;
    v.Y++;
    return v;
}
 
public static Vector operator --(Vector v)
{
    v.X--;
    v.Y--;
    return v;
}
Чтобы проверить эти операторы, обновите и выполните метод Main:

static void Main(string[] args)
{
    Vector v1 = new Vector(4, 11);
 
    v1++;
    Console.WriteLine("({0},{1})", v1.X, v1.Y);     // "(5,12)"
 
    v1--;Console.WriteLine("({0},{1})", v1.X, v1.Y);     //  "(4,11)"
}
Создание оператора отрицания

Последний арифметический унарный оператор, который будет рассмотрен в этой статье, - это оператор отрицания. Это унарная версия вычитания, используемая для идентификации отрицательной версии значения. Мы можем добавить этот оператор, используя следующий код:

public static Vector operator -(Vector v)
{
    return new Vector(-v.X, -v.Y);
}
Чтобы проверить оператор отрицания, обновите метод Main и запустите программу.

static void Main(string[] args)
{
    Vector v1 = new Vector(4, 11);
 
    Vector v2 = -v1;
    Console.WriteLine("({0},{1})", v2.X, v2.Y);     // "(-4,-11)"
}
Автор этого материала - я - Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML - то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.

тегистатьи IT, си шарп, ООП




Отправляя сообщение я подтверждаю, что ознакомлен и согласен с политикой конфиденциальности данного сайта.




Принцесса и женихи
Поля и методы в Java: передача параметров по значению аргумента
7 оправданий шахматистов после проигрыша партии