Операции. Перегрузка операций

В языке Си шарп имеется готовый набор лексем, используемых для выполнения базовых операций над встроенными типами. Например, известно, что операция + может применяться к двум целым, чтобы дать их сумму.  Но может ли одна и та же операция + может применяться к большинству встроенных типов данных, например, для строк:

string s1 = "Иванов";
string s2 = " Сергей";
string s3 = s1 + s2;	// s3 теперь содержит "Иванов Сергей"

По сути, функциональность операции + уникальным образом базируются на представленных типах данных (строках). Когда операция + применяется к числовым типам, мы получаем арифметическую сумму операндов. Однако когда та же операция применяется к строковым типам, получается конкатенация строк.

Терминологическое примечание. Часто в русскоязычных текстах смешивают понятия «операция» и «оператор». Оператор — это наименьшая автономная часть языка программирования, команда или набор команд (составной оператор). Опера́ция — конструкция языка, аналогичная по записи математическим операциям, то есть специальный способ записи некоторых действий. Путаница связана еще и с тем, что в С и C++ присваивание и инкремент/декремент являются и операторами, и операциями.  Чаще всего, операция является частью оператора. Поэтому  далее будем употреблять термин «перегрузка операции».

Язык Си шарп предоставляет возможность строить специальные классы, которые также уникально реагируют на один и тот же набор базовых лексем (вроде операции +). Необходимо знать, что абсолютно каждую встроенную операцию C# перегружать нельзя. В  таблице описаны возможности перегрузки основных операций:

Операция C# Возможность перегрузки
+,  -,  !,  ++,  —, true, false Этот набор унарных операций может быть перегружен
+,  -,  *,  /,  %,  &,  |, ^,  <<,  >> Эти бинарные операции могут быть перегружены
==,  !=,  <,  >,  <=, >= Эти операции сравнения могут быть перегружены. C# требует совместной перегрузки «подобных» операций (т.е. <  и  >,  <= и >=,  == и  !=)
[ ] Операция [] не может быть перегружена. Аналогичную функциональность предлагают индексаторы
( ) Операция () не может быть перегружена, но ту же функциональность предоставляют специальные методы преобразования
+=,  -=,  *=,  /=,  %=,  &=,  |=,  ^=, <<=,  >>= Сокращенные операции присваивания не могут перегружаться; однако вы получаете их автоматически, перегружая соответствующую бинарную операцию

Перегрузка операторов тесно связана с перегрузкой методов. Для перегрузки оператора служит ключевое слово operator, определяющее операторный метод, который, в свою очередь, определяет действие оператора относительно своего класса. Существуют две формы операторных методов: одна — для унарных операторов, другая — для бинарных. Ниже приведена общая форма для каждой формы этих методов:

// Форма перегрузки унарной операции
public static возвращаемый_тип operator op (тип_параметра операнд)
{
// операторы
}

// Форма перегрузки бинарной операции
public static возвращаемый_тип operator op (тип_параметра1 операнд1,
тип_параметра2 операнд2)
{
// операторы
}

Вместо op подставляется перегружаемая операция, например + или  /,  а возвращаемый_тип обозначает конкретный тип значения, возвращаемого указанной операцией. Это значение может быть любого типа, но зачастую оно указывается такого же типа, как и у класса, для которого перегружается операция. Такая корреляция упрощает применение перегружаемых операций в выражениях. Для унарных операций операнд обозначает передаваемый операнд, а для бинарных операций то же самое обозначают операнд1 и операнд2. Заметим, что операторные методы должны иметь оба спецификатора типа — public и static.

Пример перегрузки бинарной операции:

using System;
namespace ПерегрузкаОпераций
{
    class Vector
    {
        // Координаты точки в трехмерном пространстве
        public int x, y, z;
        // конструктор
        public Vector(int x = 0, int y = 0, int z = 0)
        {
            this.x = x;
            this.y = y;
            this.z = z;
        }
        // Перегружаем бинарную операцию + (сложение векторов)
        public static Vector operator + (Vector v1, Vector v2)
        {
            Vector v = new Vector();
            v.x = v1.x + v2.x;
            v.y = v1.y + v2.y;
            v.z = v1.z + v2.z;
            return v;
        }
        // Перегружаем бинарную операцию - (разность векторов)
        public static Vector operator - (Vector v1, Vector v2)
        {
             Vector v = new Vector();
            v.x = v1.x - v2.x;
            v.y = v1.y - v2.y;
            v.z = v1.z - v2.z;
            return v;
        }
        public void printV(string s)
        {
            Console.WriteLine(s + x + " " + y + " " + z);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Vector V1 = new Vector(3, 4, 5);
            Vector V2 = new Vector(-3, -4, 5);
            V1.printV("Координаты первого вектора: ");
            V2.printV("Координаты второго вектора: ");
            Vector V3 = V1 + V2;    // ПЕРЕГРУЗКА!
            V3.printV("Координаты суммы векторов: ");
            V3 = V1 - V2;           // ПЕРЕГРУЗКА!
            V3.printV("Координаты разности векторов: ");
            Console.ReadLine();
        }
    }
}

Результат:Здесь выполняются операции сложения и разности двух векторов (выделено красным цветом).

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

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Пролистать наверх