Перфолента.NET. ООП. Конструируем класс. Переопределение операторов

Материал из ТХАБ.РФ
Версия от 21:23, 8 июня 2023; Админ (обсуждение | вклад) (Атрибуты переопределения специальных методов)

(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

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

Если у нас есть 2 значения типа Число, то мы можем выполнить с ними арифметическую операцию или сравнить одно число с другим. Это возможно потому, что компилятору знаком тип Число и компилятор знает, какие операции можно с ним выполнить. То же самое касается всех типов данных встроенных в язык Перфолента.Net. Для каждого из встроенных типов определен набор допустимых операций. Подробнее почитать о типах данных языка Перфолента можно в статье «Типы данных в языке Перфолента».

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

Терминология

  • Оператор – идентификатор операции.
  • Операция – действие с одним или двумя операндами.
  • Операнд – значение, являющиеся исходным данным для операции.
  • Унарная операция – действие с одним операндом.
  • Бинарная операция – действие с двумя операндами.

Переопределяемые операции

В создаваемых классах и структурах можно переопределять следующие операции:

  • Арифметические операции: +, -, *, /, %, ^
  • Операции сравнения: <, =, >, <=, <>, >=
  • Логические операции: НЕ, И, ИЛИ, ЛогИ, ЛогИЛИ, ИсклИЛИ
  • Поразрядные (побитовые) операции: БитИ, БитИЛИ, БитИсклИЛИ, <<, >>
  • Операции инкремента и декремента ++, --

Важно! Операторы И и ИЛИ при переопределении являются аналогами операторов ЛогИ и ЛогИЛИ, а оператор ИсклИЛИ является аналогом БитИсклИЛИ. Это обусловлено особенностями спецификации исполняющей среды .Net.

Переопределяемые встроенные функции

Для классов и структур можно переопределить встроенную функцию ЗнчКТипу, которая позволяет преобразовать значение одного типа к другому.

Важно! Встроенная в язык Перфолента функция ЗнчКТипу() не во всех случаях вызовет одноименный оператор ЗнчКТипу определенный в классе! Если будет найден общеизвестный в среде Net способ преобразования, то будет использован именно он! Например, если выполняется преобразование к типу Строка, то будет вызвана реализация оператора ВСтроку, даже если существует аналогичная реализация оператора ЗнчКТипу.

Переопределяемые методы типа Объект

Для классов и структур можно переопределить следующие методы типа Объект: ВСтроку, ПолучитьХешКод и Эквивалентно.

Указанные методы можно вызвать для экземпляра объекта любого типа, т.к. все типы в Net являются наследниками типа Объект.

Синтаксис переопределения операторов

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

Рассмотрим пример класса, в котором переопределены некоторые из указанных операторов:

Класс НеЧетноеЦелое
   
   &ВидноСборке
   Поле Значение тип Целое=0
   
   &ВидноВсем
   Конструктор(Зн тип Целое)
       Значение=Зн-?(Зн%2 = 0, 1, 0)
   КонецКонструктора
   //переопределяем оператор сложения для двух не четных целых чисел:
   Оператор +(Зн1 тип НеЧетноеЦелое, Зн2 тип НеЧетноеЦелое) тип НеЧетноеЦелое
      Возврат Новый НеЧетноеЦелое(Зн1.Значение + Зн2.Значение)
   КонецОператора
   //переопределяем оператор унарного минуса:
   Оператор -(Зн1 тип НеЧетноеЦелое) тип НеЧетноеЦелое
      Возврат Новый НеЧетноеЦелое(-Зн1.Значение)
   КонецОператора
   //переопределяем оператор умножения для двух не четных целых чисел:
   Оператор *(Зн1 тип НеЧетноеЦелое, Зн2 тип НеЧетноеЦелое) тип НеЧетноеЦелое
      Возврат Новый НеЧетноеЦелое(Зн1.Значение * Зн2.Значение)
   КонецОператора
   //переопределяем оператор ЗнчКТипу для преобразования не четного целого числа к четному:
   &РасширяетТип
   Оператор ЗнчКТипу(Зн1 тип НеЧетноеЦелое) тип ЧетноеЦелое
      Возврат Новый ЧетноеЦелое(Зн1.Значение)
   КонецОператора
   //переопределяем оператор ЗнчКТипу для преобразования четного целого числа к не четному:
   &РасширяетТип
   Оператор ЗнчКТипу(Зн1 тип ЧетноеЦелое) тип НеЧетноеЦелое
      Возврат Новый НеЧетноеЦелое(Зн1.Значение)
   КонецОператора
   //переопределяем оператор ЗнчКТипу для преобразования не четного целого числа к типу Байт:
   &СужаетТип
   Оператор ЗнчКТипу(Зн1 тип НеЧетноеЦелое) тип Байт
      Возврат Зн1.Значение
   КонецОператора
   
   //переопределяем метод ВСтроку для преобразования не четного целого числа к типу Строка:
   Оператор ВСтроку тип Строка
       Возврат "{НечетноеЦелое: "+Значение.ВСтроку+"}"
   КонецОператора
   
   //переопределяем метод Эквивалентно для сравнения не четного целого числа с другим объектом:
   Оператор Эквивалентно(ОбъектСравнения тип Объект) тип Булево
       Возврат Значение = Целое(ОбъектСравнения)
   КонецОператора
   
   //переопределяем метод ПолучитьХешКод для вычисления и возврата хеш кода не четного целого числа:
   Оператор ПолучитьХешКод тип Целое
       Возврат Значение.ПолучитьХешКод
   КонецОператора
   
КонецКласса

Созданный нами класс можно будет использовать только в тех операциях, операторы которых мы переопределили.

Атрибуты переопределения операций

Метод Оператор при переопределении операций может иметь атрибуты ВидноВсем и ОбщийДляКласса, однако их можно не указывать, т.к. они установлены по умолчанию.

&ВидноВсем, ОбщийДляКласса
Оператор +(Зн1 тип НеЧетноеЦелое, Зн2 тип НеЧетноеЦелое) тип НеЧетноеЦелое
     Возврат Новый НеЧетноеЦелое(Зн1.Значение + Зн2.Значение)
КонецОператора

Атрибуты переопределения функции ЗнчКТипу

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

1. произойдет потеря точности с 15 до 7 значащих цифр

2. исходное число превысит размерность типа Вещ

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

В языке Перфолента для оператора ЗнчКТипу определены 2 атрибута РасширяетТип и СужаетТип, один из которых обязательно должен быть указан.

Если принимающий тип может принять любые значения исходного типа без потери точности или данных, то такое преобразование называется расширяющим тип.

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

Если включена директива СтрогаяПроверкаТипов, то НЕ явные преобразования, сужающие тип, будут запрещены.

НЕ явные преобразования, расширяющие тип, разрешены всегда.

Метод Оператор при переопределении встроенной функции ЗнчКТипу может иметь атрибуты ВидноВсем и ОбщийДляКласса, однако их можно не указывать, т.к. они установлены по умолчанию.

&РасширяетТип, ВидноВсем, ОбщийДляКласса
Оператор ЗнчКТипу(Зн1 тип ЧетноеЦелое) тип НеЧетноеЦелое
      Возврат Новый НеЧетноеЦелое(Зн1.Значение)
КонецОператора

Атрибуты переопределения специальных методов

Метод Оператор при переопределении специальных методов ВСтроку, ПолучитьХешКод и Эквивалентно может иметь атрибуты ВидноВсем и Переопределение, однако их можно не указывать, т.к. они установлены по умолчанию.

&ВидноВсем, Переопределение
Оператор ВСтроку тип Строка
       Возврат "{НечетноеЦелое: "+Значение.ВСтроку+"}"
КонецОператора

Переопределение бинарных и унарных операций

Большинство операций являются бинарными, поэтому метод Оператор для них должен иметь два параметра, хотя бы один из которых должен представлять этот объект.

Оператор +(Зн1 тип НеЧетноеЦелое, Зн2 тип Целое) тип НеЧетноеЦелое
      Возврат Новый НеЧетноеЦелое(Зн1.Значение + Зн2)
КонецОператора

Для унарных операций метод Оператор должен иметь один параметр, тип которого должен представлять этот объект.

Оператор -(Зн1 тип НеЧетноеЦелое) тип НеЧетноеЦелое
      Возврат Новый НеЧетноеЦелое(-Зн1.Значение)
КонецОператора

Перегрузка оператора ЗнчКТипу

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

Однако, для оператора ЗнчКТипу существует исключение из этого правила!!!

Сигнатура нескольких операторов ЗнчКТипу может отличаться только типом возвращаемого значения.

&СужаетТип
Оператор ЗнчКТипу(Зн1 тип НеЧетноеЦелое) тип Байт
      Возврат Байт(Зн1.Значение)
КонецОператора
&СужаетТип
Оператор ЗнчКТипу(Зн1 тип НеЧетноеЦелое) тип Цел16
      Возврат Цел16(Зн1.Значение)
КонецОператора

Вывод: Используйте специальный вид метода – Оператор, чтобы получить возможность выполнения стандартных операций языка с созданным классом или структурой. Дополнительно, Вы можете определить специальные методы ВСтроку, ПолучитьХешКод, Эквивалентно, а также переопределить встроенную функцию ЗнчКТипу для преобразования создаваемого класса или структуры к другому типу или из другого типа.

Сергей Рогаткин 05.07.2021 16:17

См. также

Ссылки