Перфолента.NET. ООП. Конструируем класс. Методы — различия между версиями

Материал из ТХАБ.РФ
Перейти к: навигация, поиск
м (Конструктор)
м (Перекрытие методов)
 
(не показано 26 промежуточных версий этого же участника)
Строка 12: Строка 12:
 
Все компьютерные программы представляют из себя последовательность команд процессора. Для самых первых компьютеров программы писались как последовательности чисел, состоящих из нулей и единиц. Но это было слишком сложно для человека и вскоре командам процессора присвоили понятные имена. Так и получился язык программирования Ассемблер, который позволял автоматически перевести программу с понятного человеку языка в понятную процессору последовательность нулей и единиц.
 
Все компьютерные программы представляют из себя последовательность команд процессора. Для самых первых компьютеров программы писались как последовательности чисел, состоящих из нулей и единиц. Но это было слишком сложно для человека и вскоре командам процессора присвоили понятные имена. Так и получился язык программирования Ассемблер, который позволял автоматически перевести программу с понятного человеку языка в понятную процессору последовательность нулей и единиц.
  
Со временем, программы стали сильно расти в размерах и в них стало сложно разбираться. Программист писавший программу через месяц уже не мог вспомнить где в ней что происходит. Поэтому сначала программу стали делить на части, которые стали называть подпрограммами. Управление в подпрограмму передавалось по её адресу в памяти компьютера, а в конце подпрограммы был прописан обратный переход в основную ветвь программы. Однако, очень быстро программисты додумались вместо адресов давать подпрограммам имена, а вычисление адреса возврата из подпрограммы переложили на плечи компилятора. Такие именованные подпрограммы с автоматическим возвратом стали называть процедурами.
+
Со временем, программы стали сильно расти в размерах и в них стало сложно разбираться. Программист писавший программу через месяц уже не мог вспомнить где в ней что происходит. Поэтому сначала программу стали делить на части, которые стали называть подпрограммами. Управление в подпрограмму передавалось по её адресу в памяти компьютера, а в конце подпрограммы был прописан обратный переход в основную ветвь программы. Однако, очень быстро программисты додумались вместо адресов давать подпрограммам имена, а вычисление адреса возврата из подпрограммы переложили на компилятор. Такие именованные подпрограммы с автоматическим возвратом стали называть процедурами.
  
 
Если Вы думаете, что это всё осталось в далёком прошлом, то нет. Сегодня тоже есть языки программирования, которые как бы остановились в этой точке развития. Обычно это языки для очень слабых процессоров, обладающих малым размером памяти, которые используются в специализированных устройствах и микроконтроллерах. Но есть и другие примеры, например, в простом языке для начинающих Small Basic у процедур нет параметров (смотрите примеры программ «Тетрис» и «Ханойские башни» в поставке Перфоленты).  
 
Если Вы думаете, что это всё осталось в далёком прошлом, то нет. Сегодня тоже есть языки программирования, которые как бы остановились в этой точке развития. Обычно это языки для очень слабых процессоров, обладающих малым размером памяти, которые используются в специализированных устройствах и микроконтроллерах. Но есть и другие примеры, например, в простом языке для начинающих Small Basic у процедур нет параметров (смотрите примеры программ «Тетрис» и «Ханойские башни» в поставке Перфоленты).  
Строка 22: Строка 22:
 
И как вишенка на торте была придумана возможность возвращать из процедуры результат вычислений. В результате чего появились функции.
 
И как вишенка на торте была придумана возможность возвращать из процедуры результат вычислений. В результате чего появились функции.
  
Зафиксируем для себя, процедуры и функции — это именованные части программы, в которые можно передать параметры, а возврат из них происходит в то место программы, откуда они были вызваны. В отличие от процедуры, которая просто возвращает управление, функция возвращает в вызвавший её код результат своей работы – данные определенного типа.
+
Зафиксируем для себя, процедуры и функции — это именованные части программы, в которые можно передать параметры, а возврат из них происходит в то место программы, откуда они были вызваны. В отличие от процедуры, которая просто возвращает управление программой в то место откуда её вызвали, функция возвращает в вызвавший её код результат своей работы – данные определенного типа.
  
 
Процедур и функций программистам хватало много лет, и даже сегодня используются языки программирования, в которых процедуры и/или функции являются основой программы. Но прогресс на месте не стоял. Следующим шагом перевернувшим мир программирования стало появление ООП – объектно-ориентированного программирования.
 
Процедур и функций программистам хватало много лет, и даже сегодня используются языки программирования, в которых процедуры и/или функции являются основой программы. Но прогресс на месте не стоял. Следующим шагом перевернувшим мир программирования стало появление ООП – объектно-ориентированного программирования.
 +
 +
см. также [[Объектно Ориентированное-Программирование простое описание]]
  
 
=== Методы объектов ===
 
=== Методы объектов ===
Строка 34: Строка 36:
 
В языке Перфолента весь исполняемый код программы находится в различных видах методов, а сами методы находятся в различных видах классов. Для успешного написания программ необходимо знать назначение каждого из возможных видов методов.
 
В языке Перфолента весь исполняемый код программы находится в различных видах методов, а сами методы находятся в различных видах классов. Для успешного написания программ необходимо знать назначение каждого из возможных видов методов.
  
=== Виды методов ===
+
=== Виды стандартных методов Перфоленты ===
  
 
В языке Перфолента имеются такие виды методов:
 
В языке Перфолента имеются такие виды методов:
  
* [[Конструктор]] – метод инициализации полей класса или структуры;
+
* [[Конструктор]] – метод инициализации полей класса или структуры
* [[Деструктор]] – метод для очистки и освобождения НЕ управляемых ресурсов;
+
* [[Деструктор]] – метод для очистки и освобождения НЕ управляемых ресурсов
* [[Завершитель]] – метод для очистки и освобождения управляемых ресурсов;
+
* [[Завершитель]] – метод для очистки и освобождения управляемых ресурсов
* [[Функция]] (синоним Метод) – метод общего назначения возвращающий результат;
+
* [[Функция]] (синоним Метод) – метод общего назначения возвращающий результат
* [[Процедура]] (синоним Метод)  – метод общего назначения НЕ возвращающий результат;
+
* [[Процедура]] (синоним Метод)  – метод общего назначения НЕ возвращающий результат
* [[Оператор]] – метод для переопределения операторов языка или для выполнения преобразований типа;
+
* [[Оператор]] – метод для переопределения операторов языка или для выполнения преобразований типа
* [[Получить]] – метод Свойства, служащий для получения значения;
+
* [[Получить]] – метод [[Свойства]], служащий для получения значения
* [[Установить]] – метод Свойства, служащий для установки значения;
+
* [[Установить]] – метод Свойства, служащий для установки значения
* [[Добавить]] – метод События, служащий для добавления получателя события;
+
* [[Добавить]] – метод [[События]], служащий для добавления получателя события
* [[Удалить]] – метод События, служащий для удаления получателя события;
+
* [[Удалить]] – метод События, служащий для удаления получателя события
* [[Вызвать]] – метод События, служащий для одновременного вызова события для всех получателей;
+
* [[Вызвать]] – метод События, служащий для одновременного вызова события для всех получателей
  
 
Посмотрим на класс, в котором имеются все доступные виды методов:
 
Посмотрим на класс, в котором имеются все доступные виды методов:
  
 
  Класс МойКласс
 
  Класс МойКласс
             // метод, служащий для инициализации полей класса
+
             // метод Конструктор, служащий для инициализации полей класса
 
             &ВидноВсем
 
             &ВидноВсем
 
             Конструктор
 
             Конструктор
Строка 59: Строка 61:
 
             КонецКонструктора
 
             КонецКонструктора
  
             // метод без параметров
+
             // метод МояПроцедура1 без параметров
 
             Процедура МояПроцедура1
 
             Процедура МояПроцедура1
 
                         //код метода
 
                         //код метода
 
             КонецПроцедуры
 
             КонецПроцедуры
  
             // метод без параметров возвращающий результат
+
             // метод МояФункция1 без параметров возвращающий результат
 
             Функция МояФункция1 тип Булево
 
             Функция МояФункция1 тип Булево
 
                         //код метода
 
                         //код метода
Строка 84: Строка 86:
 
             КонецПроцедуры
 
             КонецПроцедуры
  
             // метод, принимающий параметр и возвращающий результат
+
             // метод МояФункция3, принимающий параметр ИмяПараметра и возвращающий результат
 
             Функция МояФункция3( ИмяПараметра тип Строка) тип Булево
 
             Функция МояФункция3( ИмяПараметра тип Строка) тип Булево
 
                         //код метода
 
                         //код метода
 
             КонецФункции
 
             КонецФункции
  
             // метод, служащий для переопределения операторов языка
+
             // метод, служащий для [[переопределения операторов]] языка
             Оператор +(Операнд1 тип МойКласс, Операнд2 тип МойКласс) тип МойКласс
+
             [[Оператор]] +(Операнд1 тип МойКласс, Операнд2 тип МойКласс) тип МойКласс
 
                         //код метода
 
                         //код метода
 
             КонецОператора
 
             КонецОператора
  
             // метод, служащий для преобразования значения одного типа в значение другого типа
+
             // метод ЗнчКТипу, служащий для преобразования значения одного типа (МойКласс) в значение другого типа (ДругойКласс)
 
             Оператор ЗнчКТипу(ОбъектИсходногоТипа тип МойКласс) тип ДругойКласс
 
             Оператор ЗнчКТипу(ОбъектИсходногоТипа тип МойКласс) тип ДругойКласс
 
                         //код метода
 
                         //код метода
 
             КонецОператора
 
             КонецОператора
  
             // метод, служащий для преобразования экземпляра объекта этого класса в строку
+
             // метод ВСтроку, служащий для преобразования экземпляра объекта этого класса в строку
 
             Оператор ВСтроку тип Строка
 
             Оператор ВСтроку тип Строка
 
                         //код метода
 
                         //код метода
 
             КонецОператора
 
             КонецОператора
  
             // метод, служащий для освобождения и очистки управляемых ресурсов
+
             // метод [[Завершитель]], служащий для освобождения и очистки управляемых ресурсов
 
             Завершитель
 
             Завершитель
 
                         //код метода
 
                         //код метода
 
             КонецЗавершителя
 
             КонецЗавершителя
  
             // метод, служащий для освобождения и очистки НЕ управляемых ресурсов
+
             // метод [[Деструктор]], служащий для освобождения и очистки НЕ управляемых ресурсов
 
             Деструктор
 
             Деструктор
 
                         //код метода
 
                         //код метода
 
             КонецДеструктора
 
             КонецДеструктора
  
             // некоторые методы могут находиться только внутри свойства
+
             // некоторые методы Получить/Установить могут находиться только внутри свойства
             &ВидноВсем
+
             [[&ВидноВсем]]
             Свойство Полное Имя тип Строка
+
             '''Свойство''' ПолноеИмя тип Строка
  
                 //метод для получения значения свойства
+
                 //метод [[Получить]] для получения значения свойства
                 Получить
+
                 '''Получить'''
 
                         //код метода
 
                         //код метода
 
                 КонецПолучить
 
                 КонецПолучить
 
                  
 
                  
                 //метод для установки значения свойства
+
                 //метод [[Установить]] для установки значения свойства
                 Установить(НовоеЗначение тип Строка)
+
                 '''Установить'''(НовоеЗначение тип Строка)
 
                         //код метода
 
                         //код метода
 
                 КонецУстановить
 
                 КонецУстановить
Строка 132: Строка 134:
 
             // некоторые методы могут находиться только внутри события
 
             // некоторые методы могут находиться только внутри события
 
             &ВидноВсем
 
             &ВидноВсем
             Событие Полное ИмяСобытия тип ТипСобытия
+
             Событие ПолноеИмяСобытия тип ТипСобытия
  
                 //метод для добавления получателя события
+
                 //метод [[Добавить]] для добавления получателя события
 
                 Добавить(Значение тип ТипСобытия)
 
                 Добавить(Значение тип ТипСобытия)
 
                         //код метода
 
                         //код метода
 
                 КонецДобавить
 
                 КонецДобавить
 
                  
 
                  
                 //метод для удаления получателя события
+
                 //[[метод Удалить]] для удаления получателя события
 
                 Удалить(Значение тип ТипСобытия)
 
                 Удалить(Значение тип ТипСобытия)
 
                         //код метода
 
                         //код метода
 
                 КонецУдалить
 
                 КонецУдалить
                 //метод для вызова обработчика события у всех получателей
+
                 //метод Вызвать для вызова обработчика события у всех получателей
 
                 Вызвать
 
                 Вызвать
 
                         //код метода
 
                         //код метода
Строка 154: Строка 156:
 
=== Формальное определение метода ===
 
=== Формальное определение метода ===
  
Общий синтаксис метода таков:
+
Общий синтаксис метода:
  
 
  [&АтрибутыМетода]
 
  [&АтрибутыМетода]
  Метод [ИмяМетода]([&АтрибутыПараметра1] [МодификаторПараметра1] ИмяПараметра1 тип ТипПараметра1 [= ЗначениеПоУмолчанию],
+
  '''Метод''' [ИмяМетода]([&АтрибутыПараметра1] [МодификаторПараметра1] ИмяПараметра1 тип ТипПараметра1 [= ЗначениеПоУмолчанию],
 
                                         … [&АтрибутыПараметраН] [МодификаторПараметраН] ИмяПараметраН тип ТипПараметраН [=  
 
                                         … [&АтрибутыПараметраН] [МодификаторПараметраН] ИмяПараметраН тип ТипПараметраН [=  
 
  ЗначениеПоУмолчанию])
 
  ЗначениеПоУмолчанию])
 
                                             [[&АтрибутыВозвращаемогоЗначения] тип ТипВозвращаемогоЗначения]
 
                                             [[&АтрибутыВозвращаемогоЗначения] тип ТипВозвращаемогоЗначения]
 
                 [код тела метода]
 
                 [код тела метода]
  КонецМетода
+
  '''КонецМетода'''
  
 
В квадратных скобках указаны элементы, которые могут отсутствовать.
 
В квадратных скобках указаны элементы, которые могут отсутствовать.
  
Имя метода может отсутствовать, если метод специализированный, т.е. если это Конструктор, Деструктор, Завершитель, Оператор, Получить, Установить, Добавить, Удалить, Вызвать.
+
Имя метода может отсутствовать, если метод специализированный, т.е. если это [[Конструктор]], [[Деструктор]], [[Завершитель]], [[Оператор]], [[Получить]], [[Установить]], [[Добавить]], [[Удалить]], [[Вызвать]].
  
Атрибуты могут быть как у самого метода, так и у его параметров, и даже у возвращаемого значения. Набор атрибутов у разных видов методов может быть разный. Подробнее про атрибуты можно прочитать в статье «Атрибуты элементов программы».
+
Атрибуты могут быть:
 +
* у самого метода
 +
* у его параметров
 +
* у возвращаемого значения.
 +
Набор атрибутов у разных видов методов может быть разный. Подробнее про атрибуты можно прочитать в статье [[Атрибуты элементов программы]].
  
Модификаторы параметров Знач, Ссыл и Парам применяются для указания правил передачи значения в параметр, соответственно «по значению», «по ссылке», и как «массив параметров».
+
Модификаторы параметров [[Знач]], [[Ссыл]] и [[Парам]] применяются для указания правил передачи значения в параметр, соответственно «по значению», «по ссылке», и как «массив параметров».
  
 
Метод может не иметь параметров, в этом случае пустые круглые скобки не обязательны.
 
Метод может не иметь параметров, в этом случае пустые круглые скобки не обязательны.
  
Методы Функция, Оператор, Получить должны иметь возвращаемое значение.
+
Методы [[Функция]], [[Оператор]], [[Получить]] должны иметь возвращаемое значение.
  
Методы Процедура, Конструктор, Деструктор, Завершитель, Установить, Добавить, Удалить, Вызвать не могут иметь возвращаемого значения.
+
Методы [[Процедура]], [[Конструктор]], [[Деструктор]], [[Завершитель]], [[Установить]], [[Добавить]], [[Удалить]], [[Вызвать]] не могут иметь возвращаемого значения.
  
 
=== Сигнатура метода ===
 
=== Сигнатура метода ===
  
Сигнатурой метода называется сочетание полного имени метода (вместе с пространством имен и именами классов в которые вложен метод) и типов всех его параметров. Тип возвращаемого значения в сигнатуру не входит.
+
Сигнатурой метода называется сочетание полного имени метода (вместе с [[пространством имен]] и [[именами классов]] в которые вложен метод) и '''типов всех его параметров'''. Тип возвращаемого значения в сигнатуру не входит.
  
 
Сигнатуры методов используются при перегрузке методов, т.е. когда существует несколько методов с одинаковым именем, но с разным набором параметров.
 
Сигнатуры методов используются при перегрузке методов, т.е. когда существует несколько методов с одинаковым именем, но с разным набором параметров.
  
Существует одно исключение, когда тип возвращаемого значения учитывается в сигнатуре – это Оператор ЗнчКТипу. Могут существовать несколько методов Оператор ЗнчКТипу у которых одинаковый тип параметра, но различные типы возвращаемого значения.
+
Существует одно исключение, когда тип возвращаемого значения учитывается в сигнатуре – это [[Оператор]] [[ЗнчКТипу]]. Могут существовать несколько методов Оператор ЗнчКТипу у которых одинаковый тип параметра, но различные типы возвращаемого значения.
  
 
=== Передача параметров ===
 
=== Передача параметров ===
Строка 190: Строка 196:
 
Язык Перфолента является дружелюбным языком для программистов 1С, однако, передача параметров в методы происходит не так, как в языке 1С, и это один из важных моментов о которых программистам 1С надо помнить при переключении с одного языка на другой.
 
Язык Перфолента является дружелюбным языком для программистов 1С, однако, передача параметров в методы происходит не так, как в языке 1С, и это один из важных моментов о которых программистам 1С надо помнить при переключении с одного языка на другой.
  
Наиболее важным отличием является то, что в языке Перфолента по умолчанию параметры передаются по значению, а в языке 1С по умолчанию параметры передаются по ссылке.
+
Наиболее важным отличием является то, что '''в языке Перфолента по умолчанию параметры передаются по значению''', а в языке 1С по умолчанию параметры передаются по ссылке.
  
Фактический параметр – это значение (с учетом типа), которое передаётся методу при вызове.
+
'''Фактический параметр''' – это значение (с учетом типа), которое передаётся методу при вызове, т.е. просто данные.
  
Формальный параметр – это имя параметра метода (с учетом типа), которое получит значение при вызове метода.
+
'''Формальный параметр''' – это имя параметра метода (с учетом типа), которое получит значение при вызове метода, т.е. в качестве параметра функции указывается не число, а имя переменной в которой хранится число.
  
 
В качестве фактических параметров при вызове метода могут быть подставлены литералы простых типов. Передача литералов по ссылке хотя и возможна, но смысла не имеет.
 
В качестве фактических параметров при вызове метода могут быть подставлены литералы простых типов. Передача литералов по ссылке хотя и возможна, но смысла не имеет.
Строка 210: Строка 216:
 
Если типы значений, передаваемых методу в качестве фактических параметров, не совпадают с типами формальных параметров метода, то компилятор постарается выполнить приведение типов фактических параметров к типам формальных. Если одноименных методов, которые можно вызвать, выполнив преобразования типов, найдется несколько, то выбран будет тот, для которого необходимо сделать меньше преобразований.
 
Если типы значений, передаваемых методу в качестве фактических параметров, не совпадают с типами формальных параметров метода, то компилятор постарается выполнить приведение типов фактических параметров к типам формальных. Если одноименных методов, которые можно вызвать, выполнив преобразования типов, найдется несколько, то выбран будет тот, для которого необходимо сделать меньше преобразований.
  
===Модификаторы ===
+
==== Модификаторы ====
  
 
Как было указано выше, параметры могут передаваться в метод по ссылке, по значению или как массив параметров.
 
Как было указано выше, параметры могут передаваться в метод по ссылке, по значению или как массив параметров.
  
Для передачи по значению используется модификатор Знач, который можно не указывать, т.к. он используется по умолчанию.
+
Для передачи по значению используется модификатор [[Знач]], который можно не указывать, т.к. он используется по умолчанию.
  
Для передачи по ссылке используется модификатор Ссыл.
+
Для передачи по ссылке используется модификатор [[Ссыл]].
  
Для передачи нескольких параметров, как массива параметров используется модификатор Парам. Модификатор Парам может применяться только к последнему параметру в списке параметров, причем тип параметра должен представлять одномерный массив.
+
Для передачи нескольких параметров, как массива параметров используется модификатор [[Парам]]. Модификатор Парам может применяться '''только к последнему параметру в списке параметров''', причем тип параметра должен представлять '''одномерный массив'''.
  
 
  Процедура МояПроцедура(Знач ПараметрПоЗначению тип Число,
 
  Процедура МояПроцедура(Знач ПараметрПоЗначению тип Число,
                                                          Ссыл ПараметрПоСсылке тип Строка,
+
                        Ссыл ПараметрПоСсылке тип Строка,
                                                          Парам МассивПараметров тип Целое[])
+
                    '''Парам''' МассивПараметров тип Целое[])
 
                   //код метода
 
                   //код метода
 
  КонецПроцедуры
 
  КонецПроцедуры
  
Если у метода есть параметр, отмеченный модификатором Парам, то этому методу можно передать неограниченное число параметров, которые будут автоматически упакованы в массив и в виде массива будут переданы методу. Например, для приведенного выше метода может быть написан вызов с числом параметров больше 3-х:
+
Если у метода есть параметр, отмеченный модификатором [[Парам]], то этому методу можно передать неограниченное число параметров, которые будут автоматически упакованы в массив и в виде массива будут переданы методу. Например, для приведенного выше метода может быть написан вызов с числом параметров больше 3-х:
  
 
  МояПроцедура(7.7, "Моя строка", 3, 5, 7)
 
  МояПроцедура(7.7, "Моя строка", 3, 5, 7)
Строка 236: Строка 242:
 
Все параметры, начиная с третьего, будут упакованы в массив чисел и этот массив будет передан в параметр МассивПараметров.
 
Все параметры, начиная с третьего, будут упакованы в массив чисел и этот массив будет передан в параметр МассивПараметров.
  
=== Передача параметра по значению ===
+
==== Передача параметра по значению ====
  
 
Передача параметра по значению означает передачу методу копии значения.
 
Передача параметра по значению означает передачу методу копии значения.
Строка 242: Строка 248:
 
Это защищает исходную переменную от непредвиденного изменения её значения внутри метода, но требует дополнительных расходов памяти и времени процессора на копирование значения. Поэтому не рекомендуется передавать по значению структуры большого размера, чтобы не снижать производительность программы.
 
Это защищает исходную переменную от непредвиденного изменения её значения внутри метода, но требует дополнительных расходов памяти и времени процессора на копирование значения. Поэтому не рекомендуется передавать по значению структуры большого размера, чтобы не снижать производительность программы.
  
Передача по значению отличается для ссылочных и структурных типов данных. Для ссылочных типов по значению передаётся копия ссылки, а не копия данных объекта, а вот для структурных типов по значению передаётся копия самой структуры, т.е. того участка памяти, в котором располагается структура.
+
Передача по значению отличается для [[Ссылочные типы данных|ссылочных]] и [[структурных типов данных]].  
 +
* для ссылочных типов по значению передаётся копия ссылки, а не копия данных объекта.
 +
* для структурных типов по значению передаётся копия самой структуры, т.е. того участка памяти, в котором располагается структура.
  
В результате, можно сказать, что при передаче переменной в метод по значению, при возврате из метода значение переменной не изменится, что бы Вы не делали с переданным значением внутри метода. Ссылка на объект будет указывать на тот же объект, что и до вызова метода, а структура будет содержать те же самые значения полей, что и до вызова метода.
+
В результате, при передаче '''переменной''' в метод по значению, при возврате из метода значение переменной не изменится, что бы Вы не делали с переданным значением внутри метода. Ссылка на объект будет указывать на тот же объект, что и до вызова метода, а структура будет содержать те же самые значения полей, что и до вызова метода.
  
Однако, если Вы передали методу по значению ссылку на объект, то с самим объектом внутри метода могут произойти любые изменения. Могут измениться значения его полей и свойств, и даже содержимое других объектов, хранящихся в полях и свойствах. Гарантируется только то, что при возврате из метода ссылка по-прежнему будет указывать на тот же объект.
+
Однако, если Вы передали методу по значению '''ссылку на объект''', то с '''самим объектом внутри метода могут произойти любые изменения'''. Могут измениться значения его полей и свойств, и даже '''содержимое других объектов, хранящихся в полях и свойствах'''. Гарантируется только то, что при возврате из метода ссылка по-прежнему будет указывать на тот же объект.
  
=== Передача параметра по ссылке ===
+
==== Передача параметра по ссылке ====
  
Если Вы передали в метод переменную по ссылке, то в этом случае после возврата из метода переменная ссылочного типа может содержать ссылку на другой объект, а структура может содержать совсем другие значения полей.
+
Если Вы передали в метод переменную по ссылке, то в этом случае после возврата из метода [[переменная ссылочного типа]] может содержать ссылку на другой объект, а структура может содержать совсем другие значения полей.
  
Существуют две уважительных причины, при наличии одной из которых Вы можете использовать передачу параметра по ссылке:
+
Существуют 2 уважительных причины, при наличии одной из которых Вы можете использовать передачу параметра по ссылке:
  
 
* Возврат значения из метода через параметр
 
* Возврат значения из метода через параметр
Строка 259: Строка 267:
 
В остальных случаях используйте передачу параметров по значению.
 
В остальных случаях используйте передачу параметров по значению.
  
=== Передача строковых параметров ===
+
==== Передача строковых параметров ====
  
Строки стоят особняком среди всех объектов из-за принципа неизменности строк, который используется в .Net. Строка, находящаяся в памяти компьютера, не может быть изменена. Даже если вам надо изменить или добавить всего один символ, то в любом случае будет создана новая строка, а её старый вариант попадет под сборку мусора. Любая операция, изменяющая строку, на самом деле создаёт новую строку, содержащую необходимые изменения.
+
Строки стоят особняком среди всех объектов из-за '''принципа неизменности строк''', который используется в .Net. Строка, находящаяся в памяти компьютера, не может быть изменена. Даже если вам надо изменить или добавить всего один символ, то в любом случае будет создана новая строка, а её старый вариант попадет под сборку мусора. Любая операция, изменяющая строку, на самом деле создаёт новую строку, содержащую необходимые изменения.
  
 
Из-за указанного принципа неизменности строк, передача строки по ссылке с последующим изменением её внутри метода, приведет к тому, что после возврата из метода переменная будет ссылаться на другую строку, даже если Вам кажется, что Вы просто изменили переданную строку.
 
Из-за указанного принципа неизменности строк, передача строки по ссылке с последующим изменением её внутри метода, приведет к тому, что после возврата из метода переменная будет ссылаться на другую строку, даже если Вам кажется, что Вы просто изменили переданную строку.
Строка 274: Строка 282:
 
  Стр1 = "Моя строка"
 
  Стр1 = "Моя строка"
 
  Стр2 = Стр1
 
  Стр2 = Стр1
  ВыводСтроки Стр1 Это Стр2 //покажет Да, обе переменные ссылаются на один и тот же объект
+
  ВыводСтроки Стр1 '''Это''' Стр2 //покажет Да, обе переменные ссылаются на один и тот же объект
 
  ИзменитьСтроку(Стр2)
 
  ИзменитьСтроку(Стр2)
  ВыводСтроки Стр1 Это Стр2 //покажет Нет, переменная Стр2 ссылается на другой объект!
+
  ВыводСтроки Стр1 '''Это''' Стр2 //покажет Нет, переменная Стр2 ссылается на другой объект!
 
  ВыводСтроки Стр1 = Стр2 //покажет Да, т.к. строки равны
 
  ВыводСтроки Стр1 = Стр2 //покажет Да, т.к. строки равны
  
Обратите внимание на последние две строки кода! Несмотря на то, что посимвольно строки, хранящиеся в переменных Стр1 и Стр2, равны, на самом деле это разные объекты, хранящиеся в разных областях памяти!!! Мы просто делали замену символов в строке, но всё равно получили другой объект типа Строка.
+
Обратите внимание на последние 2 строки кода! Несмотря на то, что посимвольно строки, хранящиеся в переменных Стр1 и Стр2, равны, на самом деле это разные объекты, хранящиеся в разных областях памяти!!! Мы просто делали замену символов в строке, но всё равно получили другой объект типа Строка.
  
А что произойдет при передаче строки по значению? Строка – это ссылочный тип и в процедуру по значению будет передана копия ссылки на строку, а не копия строки. Поэтому после возврата из метода в переменной Стр2 будет ссылка на тот же объект, что и до вызова метода. А это значит, что все изменения строки, сделанные внутри метода, просто пропадут, т.к. измененная строка — это другой объект.
+
А что произойдет при передаче строки по значению? Строка – это ссылочный тип и в процедуру по значению будет передана копия ссылки на строку, а не копия строки. Поэтому после возврата из метода в переменной Стр2 будет ссылка на тот же объект, что и до вызова метода. А это значит, что '''все изменения строки, сделанные внутри метода, просто пропадут''', т.к. измененная строка — это другой объект.
  
Кроме особенностей при передаче строки в параметры методов, принцип неизменности строк может приводить к большим потерям производительности. Например, если Вы в цикле будете добавлять к большой строке по одному символу, то Вы будете на каждой итерации создавать новую копию большой строки, что будет работать очень медленно. Для ускорения работы используйте объект стандартной библиотеки ПостроительТекста, который позволяет собирать большой текст из множества маленьких частей, не теряя в производительности.
+
Кроме особенностей при передаче строки в параметры методов, принцип неизменности строк может приводить к большим потерям производительности. Например, если Вы в цикле будете добавлять к большой строке по одному символу, то Вы будете на каждой итерации создавать новую копию большой строки, что будет работать очень медленно. Для ускорения работы используйте объект стандартной библиотеки '''ПостроительТекста''', который позволяет собирать большой текст из множества маленьких частей, не теряя в производительности.
  
=== Передача массивов ===
+
==== Передача массивов ====
  
Массивы являются обычными ссылочными объектами. Если передать переменную содержащую массив в метод по значению, то после возврата из метода переменная всегда будет ссылаться на тот же массив, а при передаче по ссылке возможно, что это будет другой массив. Однако, Вы можете изменить содержимое массива, не зависимо от того, передали Вы его по ссылке или по значению.
+
Массивы являются обычными ссылочными объектами. Если передать переменную содержащую массив в метод по значению, то после возврата из метода переменная всегда будет ссылаться на тот же массив, а при передаче по ссылке возможно, что это будет другой массив. Однако, Вы можете изменить содержимое массива, не зависимо от того, передали Вы его по ссылке или по значению.
  
=== Передача элементов массивов ===
+
==== Передача элементов массивов ====
  
 
Элементы массивов передаются в метод так же, как и переменные, т.е. поведение будет зависеть от типа элемента массива и модификатора параметра.  Перед передачей по значению, значение извлекается из массива, а при передаче по ссылке передаётся ссылка на область памяти где хранится значение элемента массива.
 
Элементы массивов передаются в метод так же, как и переменные, т.е. поведение будет зависеть от типа элемента массива и модификатора параметра.  Перед передачей по значению, значение извлекается из массива, а при передаче по ссылке передаётся ссылка на область памяти где хранится значение элемента массива.
Строка 297: Строка 305:
 
Если для параметра метода указать значение по умолчанию, то при вызове метода параметр получит это значение, если для него не будет указано фактическое значение.
 
Если для параметра метода указать значение по умолчанию, то при вызове метода параметр получит это значение, если для него не будет указано фактическое значение.
  
Значения по умолчанию могут быть только константными выражениями, т.е. вычисляемыми на этапе компиляции.
+
'''Значения по умолчанию могут быть только константными выражениями''', т.е. вычисляемыми на этапе компиляции.
  
 
  Процедура УмножитьНаЧисло(ПервоеЧисло тип Число = 1, ВтороеЧисло тип Число = 3-2) тип Число
 
  Процедура УмножитьНаЧисло(ПервоеЧисло тип Число = 1, ВтороеЧисло тип Число = 3-2) тип Число
Строка 312: Строка 320:
 
=== Атрибуты параметров метода ===
 
=== Атрибуты параметров метода ===
  
Атрибуты параметрам метода приходится указывать очень редко. В основном, это необходимо для указания способа передачи параметров в не управляемый код, написанный на языках, не имеющих отношения к .Net. Во вторую очередь, атрибуты используются для задания именам параметров синонимов, которые можно будет позже использовать с помощью рефлексии.
+
Атрибуты параметрам метода приходится указывать очень редко.  
 +
* В основном, это необходимо для указания способа передачи параметров в не управляемый код, написанный на языках, не имеющих отношения к .Net.  
 +
* Во вторую очередь, атрибуты используются для задания именам параметров синонимов, которые можно будет позже использовать с помощью [[рефлексии]].
  
=== Перегрузка методов ===
+
=== [[Перегрузка методов]] ===
  
 
Перфолента.Net - язык со статической типизацией. Поэтому каждый параметр метода имеет строго заданный тип. Но что делать, если метод должен принимать значения нескольких типов?
 
Перфолента.Net - язык со статической типизацией. Поэтому каждый параметр метода имеет строго заданный тип. Но что делать, если метод должен принимать значения нескольких типов?
Строка 321: Строка 331:
  
 
* Создать несколько методов с различными именами, включающими имя принимаемого типа. Например, ЗаписатьЦелое(Ц тип Целое), ЗаписатьЧисло(Ч тип Число), ЗаписатьСтроку(Стр тип Строка). Такой способ применяется в языке 1С, т.к. в нем нет перегрузки методов.
 
* Создать несколько методов с различными именами, включающими имя принимаемого типа. Например, ЗаписатьЦелое(Ц тип Целое), ЗаписатьЧисло(Ч тип Число), ЗаписатьСтроку(Стр тип Строка). Такой способ применяется в языке 1С, т.к. в нем нет перегрузки методов.
* Создать один метод принимающий параметр типа Объект. Например, Записать(О тип Объект).
+
* Создать один метод принимающий параметр типа [[Объект]]. Например, Записать(О тип Объект).
 
* Создать несколько методов с одним именем, но с параметрами разного типа. Именно этот способ называется перегрузкой методов.
 
* Создать несколько методов с одним именем, но с параметрами разного типа. Именно этот способ называется перегрузкой методов.
  
=== Модуль МойМодуль ===
+
==== Модуль МойМодуль ====
  
 
     //перегруженные методы имеют одинаковое имя, но различные наборы параметров
 
     //перегруженные методы имеют одинаковое имя, но различные наборы параметров
 
     //атрибут Перегрузка не обязательный
 
     //атрибут Перегрузка не обязательный
  
     &Перегрузка
+
     [[&Перегрузка]]
 
     Процедура Записать(Ц тип Целое)
 
     Процедура Записать(Ц тип Целое)
 
         //код метода         
 
         //код метода         
Строка 346: Строка 356:
 
  КонецМодуля     
 
  КонецМодуля     
  
Хотя [[атрибут Перегрузка]] не является обязательным, в некоторых случаях его хорошо бы указать. Например, если перегруженные методы находятся далеко друг от друга или имеют много кода. Атрибут Перегрузка сразу скажет человеку, читающему код, что есть и другие методы с таким же именем, но принимающие другой набор параметров.
+
Хотя [[атрибут]] [[Перегрузка]] не является обязательным, в некоторых случаях его хорошо бы указать. Например, если перегруженные методы находятся далеко друг от друга или имеют много кода. Атрибут Перегрузка сразу скажет человеку, читающему код, что есть и другие методы с таким же именем, но принимающие другой набор параметров.
  
 
Возвращаемое функцией значение не учитывается при перегрузке методов, поэтому в методе не может быть 2-х функций, отличающихся только возвращаемым значением.
 
Возвращаемое функцией значение не учитывается при перегрузке методов, поэтому в методе не может быть 2-х функций, отличающихся только возвращаемым значением.
Строка 356: Строка 366:
 
Рассмотрим простой пример переопределения наследником метода родителя:
 
Рассмотрим простой пример переопределения наследником метода родителя:
  
  Класс Папа
+
  '''Класс''' Папа
 
+
      [[&ВидноВсем]], [[МожетПереопределяться]]
    &ВидноВсем, МожетПереопределяться
+
      Функция ФункцияПапы() тип Строка
    Функция ФункцияПапы() тип Строка
+
          Возврат "Папа сам сделал..."
        Возврат "Папа сам сделал..."
+
      КонецФункции
    КонецФункции
+
  '''КонецКласса'''
 
 
  КонецКласса
 
 
 
Класс Сын Родитель Папа
 
   
 
    &ВидноВсем, Переопределение
 
    Функция ФункцияПапы() тип Строка
 
        Возврат "Сделал сын..."
 
    КонецФункции   
 
  
  КонецКласса
+
  '''Класс''' Сын Родитель Папа
 +
      &ВидноВсем, [[Переопределение]]
 +
      Функция ФункцияПапы() тип Строка
 +
          Возврат "Сделал сын..."
 +
      КонецФункции   
 +
'''КонецКласса'''
  
 
В этом примере в классе Сын существует точно такая же функция ФункцияПапы, как и в родительском классе Папа. Язык позволяет хранить ссылки на объекты-потомки в переменных имеющих тип класса-предка. Поэтому возникает вопрос, какая функция будет вызвана в том случае, когда объект типа Сын хранится в переменной имеющей тип Папа? Ответ такой: НЕ зависимо от типа переменной в которой хранится объект класса Сын, будет вызвана реализация метода, переопределенная потомком.
 
В этом примере в классе Сын существует точно такая же функция ФункцияПапы, как и в родительском классе Папа. Язык позволяет хранить ссылки на объекты-потомки в переменных имеющих тип класса-предка. Поэтому возникает вопрос, какая функция будет вызвана в том случае, когда объект типа Сын хранится в переменной имеющей тип Папа? Ответ такой: НЕ зависимо от типа переменной в которой хранится объект класса Сын, будет вызвана реализация метода, переопределенная потомком.
Строка 390: Строка 396:
 
  ВыводСтроки Папа.ФункцияПапы //выводит «Сделал сын...»
 
  ВыводСтроки Папа.ФункцияПапы //выводит «Сделал сын...»
  
Обратите внимание, что для включения механизма переопределения, метод предка должен иметь один из атрибутов МожетПереопределяться или ДолженПереопределяться, а метод потомка должен иметь атрибут Переопределение.
+
Обратите внимание, что для включения механизма переопределения, метод предка должен иметь один из атрибутов [[&МожетПереопределяться]] или [[ДолженПереопределяться]], а метод потомка должен иметь атрибут [[&Переопределение|Переопределение]].
  
Программист, конструирующий класс, должен заранее продумать, какие методы можно будет переопределять в классах-наследниках, а какие нет. Любой метод можно отметить одним из трёх атрибутов МожетПереопределяться, НеМожетПереопределяться, ДолженПереопределяться.
+
Программист, конструирующий класс, должен заранее продумать, какие методы можно будет переопределять в классах-наследниках, а какие нет. Любой метод можно отметить одним из трёх атрибутов [[МожетПереопределяться]], [[НеМожетПереопределяться]], [[ДолженПереопределяться]].
  
 
По умолчанию методы родителя переопределяться не могут.
 
По умолчанию методы родителя переопределяться не могут.
  
Атрибут ДолженПереопределяться может использоваться только в абстрактных классах, имеющих атрибут ДолженНаследоваться.
+
Атрибут [[ДолженПереопределяться]] может использоваться только в [[абстрактных классах]], имеющих атрибут [[ДолженНаследоваться]].
  
=== Перекрытие методов ===
+
==== Перекрытие методов ====
  
 
Переопределение метода полностью закрывает доступ к функциональности исходного метода предка, т.к. в любом случае вызывается переопределённый метод потомка. Но иногда, способность вызывать метод предка необходимо сохранить. Причины могут быть разными. Например, без вызова метода предка его класс может работать не корректно, или в нём реализована уникальная функциональность, которую в переопределённом методе повторить невозможно.
 
Переопределение метода полностью закрывает доступ к функциональности исходного метода предка, т.к. в любом случае вызывается переопределённый метод потомка. Но иногда, способность вызывать метод предка необходимо сохранить. Причины могут быть разными. Например, без вызова метода предка его класс может работать не корректно, или в нём реализована уникальная функциональность, которую в переопределённом методе повторить невозможно.
  
В таких случаях можно воспользоваться перекрытием методов, которое позволяет через переменную имеющую тип предка вызывать метод предка, а через переменную имеющую тип потомка вызывать метод потомка.
+
В таких случаях можно воспользоваться перекрытием методов, которое позволяет
 +
* через переменную имеющую тип предка вызывать метод предка
 +
* через переменную имеющую тип потомка вызывать метод потомка.
  
 
Рассмотрим предыдущий пример с перекрытием вместо переопределения:
 
Рассмотрим предыдущий пример с перекрытием вместо переопределения:
  
 
  Класс Папа
 
  Класс Папа
     &ВидноВсем, МожетПереопределяться
+
     &[[ВидноВсем]], [[МожетПереопределяться]]
 
     Функция ФункцияПапы() тип Строка
 
     Функция ФункцияПапы() тип Строка
 
         Возврат "Папа сам сделал..."
 
         Возврат "Папа сам сделал..."
Строка 414: Строка 422:
  
 
  Класс Сын Родитель Папа
 
  Класс Сын Родитель Папа
     &ВидноВсем, Перекрытие
+
     &ВидноВсем, [[Перекрытие]]
 
     Функция ФункцияПапы() тип Строка
 
     Функция ФункцияПапы() тип Строка
 
         Возврат "Сделал сын..."
 
         Возврат "Сделал сын..."
Строка 438: Строка 446:
 
Для наглядности, перекрытие методов можно сравнить с перекрытием между этажами жилого дома. Вы не можете дотянуться до холодильника на другом этаже, пока не перейдете на этот этаж.  
 
Для наглядности, перекрытие методов можно сравнить с перекрытием между этажами жилого дома. Вы не можете дотянуться до холодильника на другом этаже, пока не перейдете на этот этаж.  
  
Атрибут Перекрытие может использоваться в тех же ситуациях, что и атрибут Переопределение.
+
Атрибут [[Перекрытие]] может использоваться в тех же ситуациях, что и атрибут [[Переопределение]].
  
Дополнительную информацию о Перегрузке, Переопределении и Перекрытии свойств и методов можно почерпнуть из статей «[[Принципы ООП. Наследование.]]», «[[Принципы ООП. Инкапсуляция.]]» и «[[Принципы ООП. Полиморфизм.]]» (пока не опубликованы, ожидаются в ближайшее время).
+
Дополнительную информацию о [[Перегрузке]], [[Переопределении]] и [[Перекрытии]] свойств и методов можно почерпнуть из статей
 +
* «[[Принципы ООП. Наследование.]]»,  
 +
* «[[Принципы ООП. Инкапсуляция.]]»  
 +
* и «[[Принципы ООП. Полиморфизм.]]»
 +
(пока не опубликованы, ожидаются в ближайшее время).
  
 
===Специализированные методы ===
 
===Специализированные методы ===
Строка 448: Строка 460:
 
==== Конструктор ====
 
==== Конструктор ====
  
Конструктор — это специализированный метод, который применяется для начальной инициализации полей классов и структур при их создании оператором Новый.  Конструкторы подробно описаны в статье «Перфолента.NET. ООП. Конструируем класс. Конструкторы».
+
Конструктор — это специализированный метод, который применяется для начальной инициализации полей классов и структур при их создании [[оператором Новый]].  Конструкторы подробно описаны в статье [[Перфолента.NET. ООП. Конструируем класс. Конструкторы]].
  
 
==== Завершитель и Деструктор ====
 
==== Завершитель и Деструктор ====
  
Завершитель и Деструктор — это два специализированных метода класса, предназначенных для освобождения и очистки управляемых и НЕ управляемых ресурсов, используемых экземплярами объектов, созданных во время выполнения программы. Методы Завершитель и Деструктор должны вызываться либо пользователем, либо сборщиком мусора тогда, когда экземпляр объекта больше не нужен и занятые им ресурсы необходимо освободить. Завершители и Деструкторы подробно описаны в статье «Конструируем класс. Завершители и Деструкторы.
+
Завершитель и Деструктор — это два специализированных метода класса, предназначенных для освобождения и очистки управляемых и НЕ управляемых ресурсов, используемых экземплярами объектов, созданных во время выполнения программы. Методы Завершитель и Деструктор должны вызываться либо пользователем, либо сборщиком мусора тогда, когда экземпляр объекта больше не нужен и занятые им ресурсы необходимо освободить. Завершители и Деструкторы подробно описаны в статье [[Конструируем класс. Завершители и Деструкторы]].
  
 
==== Оператор ====
 
==== Оператор ====
Строка 464: Строка 476:
 
Свойство, в полном синтаксисе, может иметь один или оба метода Получить и Установить, которые служат соответственно для получения и установки значения свойства.
 
Свойство, в полном синтаксисе, может иметь один или оба метода Получить и Установить, которые служат соответственно для получения и установки значения свойства.
  
Свойства и их методы подробно описаны в статье «Конструируем класс. Свойства.  
+
Свойства и их методы подробно описаны в статье [[Конструируем класс. Свойства]].
  
 
==== Методы события ====  
 
==== Методы события ====  
  
Событие, в полном синтаксисе, может иметь все или некоторые из методов Добавить, Удалить и Вызвать.
+
Событие, в полном синтаксисе, может иметь все или некоторые из методов [[Добавить]], [[Удалить]] и [[Вызвать]].
  
События и их методы подробно будут описаны в статье «Конструируем класс. События.» (пока не опубликована, ожидается в ближайшее время).  
+
События и их методы подробно будут описаны в статье «[[Конструируем класс. События]]» (пока не опубликована, ожидается в ближайшее время).  
  
 
'''Вывод:''' Методы содержат весь исполняемый код программы. Существуют различные виды методов: специализированные и методы общего назначения.
 
'''Вывод:''' Методы содержат весь исполняемый код программы. Существуют различные виды методов: специализированные и методы общего назначения.

Текущая версия на 00:38, 9 июня 2023

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

Методы класса - это набор действий, которые сможет выполнять объект созданный на базе этого класса

Методы класса - это набор действий, которые сможет выполнять объект созданный на базе этого класса.

«Весь исполняемый код программы находится в методах.»
3-й закон Перфоленты.

Исторический экскурс

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

Со временем, программы стали сильно расти в размерах и в них стало сложно разбираться. Программист писавший программу через месяц уже не мог вспомнить где в ней что происходит. Поэтому сначала программу стали делить на части, которые стали называть подпрограммами. Управление в подпрограмму передавалось по её адресу в памяти компьютера, а в конце подпрограммы был прописан обратный переход в основную ветвь программы. Однако, очень быстро программисты додумались вместо адресов давать подпрограммам имена, а вычисление адреса возврата из подпрограммы переложили на компилятор. Такие именованные подпрограммы с автоматическим возвратом стали называть процедурами.

Если Вы думаете, что это всё осталось в далёком прошлом, то нет. Сегодня тоже есть языки программирования, которые как бы остановились в этой точке развития. Обычно это языки для очень слабых процессоров, обладающих малым размером памяти, которые используются в специализированных устройствах и микроконтроллерах. Но есть и другие примеры, например, в простом языке для начинающих Small Basic у процедур нет параметров (смотрите примеры программ «Тетрис» и «Ханойские башни» в поставке Перфоленты).

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

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

И как вишенка на торте была придумана возможность возвращать из процедуры результат вычислений. В результате чего появились функции.

Зафиксируем для себя, процедуры и функции — это именованные части программы, в которые можно передать параметры, а возврат из них происходит в то место программы, откуда они были вызваны. В отличие от процедуры, которая просто возвращает управление программой в то место откуда её вызвали, функция возвращает в вызвавший её код результат своей работы – данные определенного типа.

Процедур и функций программистам хватало много лет, и даже сегодня используются языки программирования, в которых процедуры и/или функции являются основой программы. Но прогресс на месте не стоял. Следующим шагом перевернувшим мир программирования стало появление ООП – объектно-ориентированного программирования.

см. также Объектно Ориентированное-Программирование простое описание

Методы объектов

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

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

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

Виды стандартных методов Перфоленты

В языке Перфолента имеются такие виды методов:

  • Конструктор – метод инициализации полей класса или структуры
  • Деструктор – метод для очистки и освобождения НЕ управляемых ресурсов
  • Завершитель – метод для очистки и освобождения управляемых ресурсов
  • Функция (синоним Метод) – метод общего назначения возвращающий результат
  • Процедура (синоним Метод) – метод общего назначения НЕ возвращающий результат
  • Оператор – метод для переопределения операторов языка или для выполнения преобразований типа
  • Получить – метод Свойства, служащий для получения значения
  • Установить – метод Свойства, служащий для установки значения
  • Добавить – метод События, служащий для добавления получателя события
  • Удалить – метод События, служащий для удаления получателя события
  • Вызвать – метод События, служащий для одновременного вызова события для всех получателей

Посмотрим на класс, в котором имеются все доступные виды методов:

Класс МойКласс
            // метод Конструктор, служащий для инициализации полей класса
           &ВидноВсем
           Конструктор
                       //код метода
           КонецКонструктора
            // метод МояПроцедура1 без параметров
           Процедура МояПроцедура1
                       //код метода
           КонецПроцедуры
            // метод МояФункция1 без параметров возвращающий результат
           Функция МояФункция1 тип Булево
                       //код метода
           КонецФункции
            // метод без параметров, синтаксический аналог процедуры
           Метод МояПроцедура2
                       //код метода
           КонецМетода
            // метод без параметров возвращающий результат, синтаксический аналог функции
           Метод МояФункция2 тип Булево
                       //код метода
           КонецМетода
            // метод, принимающий параметр
           Процедура МояПроцедура3( ИмяПараметра тип Строка)
                       //код метода
           КонецПроцедуры
            // метод МояФункция3, принимающий параметр ИмяПараметра и возвращающий результат
           Функция МояФункция3( ИмяПараметра тип Строка) тип Булево
                       //код метода
           КонецФункции
            // метод, служащий для переопределения операторов языка
           Оператор +(Операнд1 тип МойКласс, Операнд2 тип МойКласс) тип МойКласс
                       //код метода
           КонецОператора
            // метод ЗнчКТипу, служащий для преобразования значения одного типа (МойКласс) в значение другого типа (ДругойКласс)
           Оператор ЗнчКТипу(ОбъектИсходногоТипа тип МойКласс) тип ДругойКласс
                       //код метода
           КонецОператора
            // метод ВСтроку, служащий для преобразования экземпляра объекта этого класса в строку
           Оператор ВСтроку тип Строка
                       //код метода
           КонецОператора
            // метод Завершитель, служащий для освобождения и очистки управляемых ресурсов
           Завершитель
                       //код метода
           КонецЗавершителя
            // метод Деструктор, служащий для освобождения и очистки НЕ управляемых ресурсов
           Деструктор
                       //код метода
           КонецДеструктора
            // некоторые методы Получить/Установить могут находиться только внутри свойства
           &ВидноВсем
           Свойство ПолноеИмя тип Строка
               //метод Получить для получения значения свойства
               Получить
                       //код метода
               КонецПолучить
               
               //метод Установить для установки значения свойства
               Установить(НовоеЗначение тип Строка)
                       //код метода
               КонецУстановить
           КонецСвойства
            // некоторые методы могут находиться только внутри события
           &ВидноВсем
           Событие ПолноеИмяСобытия тип ТипСобытия
               //метод Добавить для добавления получателя события
               Добавить(Значение тип ТипСобытия)
                       //код метода
               КонецДобавить
               
               //метод Удалить для удаления получателя события
               Удалить(Значение тип ТипСобытия)
                       //код метода
               КонецУдалить
               //метод Вызвать для вызова обработчика события у всех получателей
               Вызвать
                       //код метода
               КонецВызвать
           КонецСобытия
КонецКласса

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

Формальное определение метода

Общий синтаксис метода:

[&АтрибутыМетода]
Метод [ИмяМетода]([&АтрибутыПараметра1] [МодификаторПараметра1] ИмяПараметра1 тип ТипПараметра1 [= ЗначениеПоУмолчанию],
                                        … [&АтрибутыПараметраН] [МодификаторПараметраН] ИмяПараметраН тип ТипПараметраН [= 
ЗначениеПоУмолчанию])
                                            [[&АтрибутыВозвращаемогоЗначения] тип ТипВозвращаемогоЗначения]
               [код тела метода]
КонецМетода

В квадратных скобках указаны элементы, которые могут отсутствовать.

Имя метода может отсутствовать, если метод специализированный, т.е. если это Конструктор, Деструктор, Завершитель, Оператор, Получить, Установить, Добавить, Удалить, Вызвать.

Атрибуты могут быть:

  • у самого метода
  • у его параметров
  • у возвращаемого значения.

Набор атрибутов у разных видов методов может быть разный. Подробнее про атрибуты можно прочитать в статье Атрибуты элементов программы.

Модификаторы параметров Знач, Ссыл и Парам применяются для указания правил передачи значения в параметр, соответственно «по значению», «по ссылке», и как «массив параметров».

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

Методы Функция, Оператор, Получить должны иметь возвращаемое значение.

Методы Процедура, Конструктор, Деструктор, Завершитель, Установить, Добавить, Удалить, Вызвать не могут иметь возвращаемого значения.

Сигнатура метода

Сигнатурой метода называется сочетание полного имени метода (вместе с пространством имен и именами классов в которые вложен метод) и типов всех его параметров. Тип возвращаемого значения в сигнатуру не входит.

Сигнатуры методов используются при перегрузке методов, т.е. когда существует несколько методов с одинаковым именем, но с разным набором параметров.

Существует одно исключение, когда тип возвращаемого значения учитывается в сигнатуре – это Оператор ЗнчКТипу. Могут существовать несколько методов Оператор ЗнчКТипу у которых одинаковый тип параметра, но различные типы возвращаемого значения.

Передача параметров

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

Наиболее важным отличием является то, что в языке Перфолента по умолчанию параметры передаются по значению, а в языке 1С по умолчанию параметры передаются по ссылке.

Фактический параметр – это значение (с учетом типа), которое передаётся методу при вызове, т.е. просто данные.

Формальный параметр – это имя параметра метода (с учетом типа), которое получит значение при вызове метода, т.е. в качестве параметра функции указывается не число, а имя переменной в которой хранится число.

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

МояПроцедура(777, 3.1415, '20210101', "Строка текста", Истина)

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

МояПроцедура(МояПеременная, МойМассив[0], ПолеЭтогоОбъекта, СвойствоЭтогоОбъекта, ПараметрТекущегоМетода)

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

МояПроцедура(ВычислитьПараметр1(), ВычислитьПараметр2(), 3+5.5^2-1, Лев("Строка текста", 6), Новый МойОбъект)

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

Модификаторы

Как было указано выше, параметры могут передаваться в метод по ссылке, по значению или как массив параметров.

Для передачи по значению используется модификатор Знач, который можно не указывать, т.к. он используется по умолчанию.

Для передачи по ссылке используется модификатор Ссыл.

Для передачи нескольких параметров, как массива параметров используется модификатор Парам. Модификатор Парам может применяться только к последнему параметру в списке параметров, причем тип параметра должен представлять одномерный массив.

Процедура МояПроцедура(Знач ПараметрПоЗначению тип Число,
                       Ссыл ПараметрПоСсылке тип Строка,
                    Парам МассивПараметров тип Целое[])
                  //код метода
КонецПроцедуры

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

МояПроцедура(7.7, "Моя строка", 3, 5, 7)

или так, если параметров больше:

МояПроцедура(7.7, "Моя строка", 3, 5, 7, 9, 11, 13, 15, 17, 19, 21)

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

Передача параметра по значению

Передача параметра по значению означает передачу методу копии значения.

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

Передача по значению отличается для ссылочных и структурных типов данных.

  • для ссылочных типов по значению передаётся копия ссылки, а не копия данных объекта.
  • для структурных типов по значению передаётся копия самой структуры, т.е. того участка памяти, в котором располагается структура.

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

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

Передача параметра по ссылке

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

Существуют 2 уважительных причины, при наличии одной из которых Вы можете использовать передачу параметра по ссылке:

  • Возврат значения из метода через параметр
  • Передача громоздкой структуры, занимающей много памяти

В остальных случаях используйте передачу параметров по значению.

Передача строковых параметров

Строки стоят особняком среди всех объектов из-за принципа неизменности строк, который используется в .Net. Строка, находящаяся в памяти компьютера, не может быть изменена. Даже если вам надо изменить или добавить всего один символ, то в любом случае будет создана новая строка, а её старый вариант попадет под сборку мусора. Любая операция, изменяющая строку, на самом деле создаёт новую строку, содержащую необходимые изменения.

Из-за указанного принципа неизменности строк, передача строки по ссылке с последующим изменением её внутри метода, приведет к тому, что после возврата из метода переменная будет ссылаться на другую строку, даже если Вам кажется, что Вы просто изменили переданную строку.

Процедура ИзменитьСтроку(Ссыл СтрокаПоСсылке тип Строка)
          //сделаем ничего не значащую замену символов в строке
          //здесь нам кажется, что мы изменяем существующую строку
          СтрокаПоСсылке = СтрЗаменить(СтрокаПоСсылке,"Моя","Моя")
КонецПроцедуры
//где-то в другом методе
Стр1 = "Моя строка"
Стр2 = Стр1
ВыводСтроки Стр1 Это Стр2 //покажет Да, обе переменные ссылаются на один и тот же объект
ИзменитьСтроку(Стр2)
ВыводСтроки Стр1 Это Стр2 //покажет Нет, переменная Стр2 ссылается на другой объект!
ВыводСтроки Стр1 = Стр2 //покажет Да, т.к. строки равны

Обратите внимание на последние 2 строки кода! Несмотря на то, что посимвольно строки, хранящиеся в переменных Стр1 и Стр2, равны, на самом деле это разные объекты, хранящиеся в разных областях памяти!!! Мы просто делали замену символов в строке, но всё равно получили другой объект типа Строка.

А что произойдет при передаче строки по значению? Строка – это ссылочный тип и в процедуру по значению будет передана копия ссылки на строку, а не копия строки. Поэтому после возврата из метода в переменной Стр2 будет ссылка на тот же объект, что и до вызова метода. А это значит, что все изменения строки, сделанные внутри метода, просто пропадут, т.к. измененная строка — это другой объект.

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

Передача массивов

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

Передача элементов массивов

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

Значения параметров по умолчанию

Если для параметра метода указать значение по умолчанию, то при вызове метода параметр получит это значение, если для него не будет указано фактическое значение.

Значения по умолчанию могут быть только константными выражениями, т.е. вычисляемыми на этапе компиляции.

Процедура УмножитьНаЧисло(ПервоеЧисло тип Число = 1, ВтороеЧисло тип Число = 3-2) тип Число
          //один или оба параметра могут быть пропущены при вызове метода, т.к. имеют значение по умолчанию
          Возврат ПервоеЧисло * ВтороеЧисло
КонецПроцедуры
//где-то в другом методе
ВыводСтроки УмножитьНаЧисло           //покажет 1, пропущены оба параметра
ВыводСтроки УмножитьНаЧисло(2)     //покажет 2, пропущен второй параметр
ВыводСтроки УмножитьНаЧисло( ,3)   //покажет 3, пропущен первый параметр
ВыводСтроки УмножитьНаЧисло(2, 3) //покажет 6, заданы оба параметра

Атрибуты параметров метода

Атрибуты параметрам метода приходится указывать очень редко.

  • В основном, это необходимо для указания способа передачи параметров в не управляемый код, написанный на языках, не имеющих отношения к .Net.
  • Во вторую очередь, атрибуты используются для задания именам параметров синонимов, которые можно будет позже использовать с помощью рефлексии.

Перегрузка методов

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

Существует 3 варианта решения:

  • Создать несколько методов с различными именами, включающими имя принимаемого типа. Например, ЗаписатьЦелое(Ц тип Целое), ЗаписатьЧисло(Ч тип Число), ЗаписатьСтроку(Стр тип Строка). Такой способ применяется в языке 1С, т.к. в нем нет перегрузки методов.
  • Создать один метод принимающий параметр типа Объект. Например, Записать(О тип Объект).
  • Создать несколько методов с одним именем, но с параметрами разного типа. Именно этот способ называется перегрузкой методов.

Модуль МойМодуль

   //перегруженные методы имеют одинаковое имя, но различные наборы параметров
   //атрибут Перегрузка не обязательный
   &Перегрузка
   Процедура Записать(Ц тип Целое)
       //код метода        
   КонецПроцедуры    
   &Перегрузка
   Процедура Записать(Ч тип Число)
       //код метода        
   КонецПроцедуры    
   &Перегрузка
   Процедура Записать(Стр тип Строка, ВВерхнемРегистре тип Булево)
       //код метода        
   КонецПроцедуры    
КонецМодуля    

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

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

Переопределение методов

Перфолента.Net – это объектно-ориентированный язык, поддерживающий наследование. Класс-потомок наследует свойства и методы всех своих предков. Но иногда, метод определенный в одном из классов-предков делает не совсем то, что необходимо потомку. В этом случае метод или свойство можно переопределить.

Рассмотрим простой пример переопределения наследником метода родителя:

Класс Папа
     &ВидноВсем, МожетПереопределяться
     Функция ФункцияПапы() тип Строка
         Возврат "Папа сам сделал..."
     КонецФункции
КонецКласса
Класс Сын Родитель Папа
     &ВидноВсем, Переопределение
     Функция ФункцияПапы() тип Строка
         Возврат "Сделал сын..."
     КонецФункции    
КонецКласса

В этом примере в классе Сын существует точно такая же функция ФункцияПапы, как и в родительском классе Папа. Язык позволяет хранить ссылки на объекты-потомки в переменных имеющих тип класса-предка. Поэтому возникает вопрос, какая функция будет вызвана в том случае, когда объект типа Сын хранится в переменной имеющей тип Папа? Ответ такой: НЕ зависимо от типа переменной в которой хранится объект класса Сын, будет вызвана реализация метода, переопределенная потомком.

//вызов функции класса Папа
Папа = Новый Папа
ВыводСтроки Папа.ФункцияПапы //выводит «Папа сам сделал...»
//вызов функции класса Сын
Сын = Новый Сын
ВыводСтроки Сын.ФункцияПапы //выводит «Сделал сын...»
//через переменную типа Папа
//вызываем функцию класса Сын
//т.к. в классе Сын функция переопределена
Папа = Сын
ВыводСтроки Папа.ФункцияПапы //выводит «Сделал сын...»

Обратите внимание, что для включения механизма переопределения, метод предка должен иметь один из атрибутов &МожетПереопределяться или ДолженПереопределяться, а метод потомка должен иметь атрибут Переопределение.

Программист, конструирующий класс, должен заранее продумать, какие методы можно будет переопределять в классах-наследниках, а какие нет. Любой метод можно отметить одним из трёх атрибутов МожетПереопределяться, НеМожетПереопределяться, ДолженПереопределяться.

По умолчанию методы родителя переопределяться не могут.

Атрибут ДолженПереопределяться может использоваться только в абстрактных классах, имеющих атрибут ДолженНаследоваться.

Перекрытие методов

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

В таких случаях можно воспользоваться перекрытием методов, которое позволяет

  • через переменную имеющую тип предка вызывать метод предка
  • через переменную имеющую тип потомка вызывать метод потомка.

Рассмотрим предыдущий пример с перекрытием вместо переопределения:

Класс Папа
   &ВидноВсем, МожетПереопределяться
   Функция ФункцияПапы() тип Строка
       Возврат "Папа сам сделал..."
   КонецФункции
КонецКласса
Класс Сын Родитель Папа
   &ВидноВсем, Перекрытие
   Функция ФункцияПапы() тип Строка
       Возврат "Сделал сын..."
   КонецФункции    
КонецКласса

Фактически мы заменили только один атрибут, однако, результат работы будет другой.

//вызов функции класса Папа
Папа = Новый Папа
ВыводСтроки Папа.ФункцияПапы //выводит «Папа сам сделал...»
//вызов функции класса Сын
Сын = Новый Сын
ВыводСтроки Сын.ФункцияПапы //выводит «Сделал сын...»
//через переменную типа Папа
//вызываем функцию класса Папа
//т.к. в классе Сын функция перекрыта
Папа = Сын
ВыводСтроки Папа.ФункцияПапы //выводит «Папа сам сделал...»

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

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

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

(пока не опубликованы, ожидаются в ближайшее время).

Специализированные методы

Некоторые методы имеют специальное назначение и специальное предопределенное имя.

Конструктор

Конструктор — это специализированный метод, который применяется для начальной инициализации полей классов и структур при их создании оператором Новый. Конструкторы подробно описаны в статье Перфолента.NET. ООП. Конструируем класс. Конструкторы.

Завершитель и Деструктор

Завершитель и Деструктор — это два специализированных метода класса, предназначенных для освобождения и очистки управляемых и НЕ управляемых ресурсов, используемых экземплярами объектов, созданных во время выполнения программы. Методы Завершитель и Деструктор должны вызываться либо пользователем, либо сборщиком мусора тогда, когда экземпляр объекта больше не нужен и занятые им ресурсы необходимо освободить. Завершители и Деструкторы подробно описаны в статье Конструируем класс. Завершители и Деструкторы.

Оператор

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

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

Методы свойства

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

Свойства и их методы подробно описаны в статье Конструируем класс. Свойства.

Методы события

Событие, в полном синтаксисе, может иметь все или некоторые из методов Добавить, Удалить и Вызвать.

События и их методы подробно будут описаны в статье «Конструируем класс. События» (пока не опубликована, ожидается в ближайшее время).

Вывод: Методы содержат весь исполняемый код программы. Существуют различные виды методов: специализированные и методы общего назначения.

Сергей Рогаткин 18.07.2021 20:01

См. также

Ссылки