В языке Си шарп имеется готовый набор лексем, используемых для выполнения базовых операций над встроенными типами. Например, известно, что операция + может применяться к двум целым, чтобы дать их сумму. Но может ли одна и та же операция + может применяться к большинству встроенных типов данных, например, для строк:
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(); } } }
Результат:Здесь выполняются операции сложения и разности двух векторов (выделено красным цветом).
Поскольку операции, также как и методы являются член-функциями класса, то не удивительно, что их определение отличается только заголовком.
NEW: Наш Чат, в котором вы можете обсудить любые вопросы, идеи, поделиться опытом или связаться с администраторами.