Руководство разработчика

Объектные типы

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

ТИП Человек
[
  СТРОКА: фамилия, имя, отчество;
  ДАТА: дата_рождения;
]

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

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

Объектные типы широко используются модулями. Так задание внешнего вида и поведения пользовательского интерфейса (GUI) в модуле FC происходит с помощью объектных типов. В данном случае объектные типы соответствуют видам форм и элементов управления.

Подробно различные аспекты использования объектных типов рассмотрены в следующих разделах справки:

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

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

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

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

Допускается замена тех или иных свойств в типе-потомке по сравнению с его предками. Такая замена называется подменой поля или метода объектного типа. При подмене полей должен сохраняться тип, а для методов – параметры и тип результата. При подмене полей, чтобы не повторять тип поля в объявлении, может использоваться ключевое слово ПОДМЕНА. Смысл подмены полей – изменение начальных значений полей для типа-потомка. Подмена метода позволяет задать иное определение в дочернем типе, что открывает возможности для полиморфизма.

Объектный тип может иметь несколько базовых интерфейсов. Интерфейсы объявляют методы, но не предоставляют их определений (т.н. абстрактные методы). Поэтому объектный тип обязан подменить все методы его базовых интерфейсов. Свойство полиморфизма для связки "интерфейс - объектный тип" работает также, как для связки объектных типов "предок - потомок". Совместное использование объектных типов и интерфейсов дает возможность динамического создание объектов, что дает широкие возможности по управлению временем жизни объекта и использованию полиморфизма. Для непосредственного доступа к объектному значению через интерфейс применяется ключевое слово ОБЪЕКТ.

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

За исключением случаев подмены, собственные и унаследованные поля и методы не должны иметь одинаковые имена. Например, объявление поля "Цена" и метода "Цена" на одной ветке дерева наследования будет ошибкой.

В исходном тексте объектный тип может быть объявлен в области объявлений (см. структура программы). Имя объявляемого типа указывается после ключевого слова ТИП. За именем типа в круглых скобках может указывается имя типа-родителя и список базовых интерфейсов. Далее в квадратных скобках располагается область объявления объектного типа. В области объявления объектного типа в произвольном порядке могут находиться объявления полей и методов.

Область объявления объектного типа может содержать открытые и закрытые объявления. Это позволяет следовать принципу инкапсуляции, когда разработчик разделяет поля и методы на доступные для внешнего использования и являющиеся деталями реализации. Соответствующие секции в области определения объектного типа обозначаются ключевыми словами ОТКРЫТО и ЗАКРЫТО.

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

Объявления методов оформляется полностью аналогично обычным функциям. Начало объявления метода обозначает ключевое слово ФУНКЦИЯ. Определение метода может быть совмещено с объявлением, тогда тело метода размещается внутри области объявлений объектного типа и завершается ключевым словом КОНЕЦ_ФУНКЦИИ. Определения методов может быть вынесено за пределы области объявления объектного типа. В этом случае после ключевого слова ФУНКЦИЯ и описания параметров ставится точка с запятой. Вынесенное определение метода может располагаться даже в другой библиотеке. Перед именем метода, в таком случае, указывается через точку имя объектного типа.

В теле методов может использоваться ключевое слово САМ, дающее доступ к значению текущего объекта в целом. Также в теле метода возможен вызов методов, определенных в типах-предках. Для этого используется ключевое слово РОДИТЕЛЬ.

Синтаксис

ТИП <имя типа>[(<родительский тип> [, <базовый интерфейс 1> [, ...]])]
[
  [ОТКРЫТО: или ЗАКРЫТО:]
  
  // поле
  <тип поля>: <имя поля> [ = <константное выражение> ];
  
  // однотипные поля
  <тип поля>: <имя поля 1> [, <имя поля 2> [, ...]];
  
  // подмена поля
  ПОДМЕНА <имя поля> = <константное выражение>;

  // объявление и определение метода
  ФУНКЦИЯ [<тип результата>:] <имя метода>[(<список параметров>)]
    // тело метода
  КОНЕЦ_ФУНКЦИИ
  
  // только объявление метода
  ФУНКЦИЯ [<тип результата>:] <имя метода>[(<список параметров>)];
]

// определение метода вне типа
ФУНКЦИЯ [<тип результата>:] <имя типа>.<имя метода>[(<список параметров>)]
  // тело метода
КОНЕЦ_ФУНКЦИИ

Примеры

Иерархия объектных типов:

// объявляем тип, содержащий информацию о человеке

ТИП Человек // имя типа-родителя опущено, следовательно, это корневой объектный тип 
[ // начало объявления типа

  // объявляем поля строкового типа, отражающие 
  // фамилию, имя и отчество человека
  СТРОКА: фамилия, имя, отчество;

  // объявляем поле типа "дата", отражающее дату рождения
  ДАТА: дата_рождения;

  // описываем метод, формирующий строку из инициалов человека с
  // помощью встроенной функции выделения подстроки ПОДСТР
  ФУНКЦИЯ СТРОКА: Инициалы
    РЕЗУЛЬТАТ = ПОДСТР(фамилия , 1, 1) + 
                ПОДСТР(имя     , 1, 1) +
                ПОДСТР(отчество, 1, 1)
  КОНЕЦ_ФУНКЦИИ

  // Описываем метод получения возраста человека (в полных годах)
  ФУНКЦИЯ ЦЕЛОЕ: Возраст
    РЕЗУЛЬТАТ = ГОД(ДАТА_ТЕК) - ГОД(дата_рождения)
  КОНЕЦ_ФУНКЦИИ

  // Описываем метод получения строки информации о человеке
  ФУНКЦИЯ СТРОКА: Информация
    РЕЗУЛЬТАТ = фамилия + " " + имя + " " + отчество +
                ", возраст: " + СТР(Возраст) + " лет"
  КОНЕЦ_ФУНКЦИИ
] // конец объявления типа

// наследуем тип Сотрудник
ТИП Сотрудник(Человек)
[
  СТРОКА: отдел;
  СТРОКА: должность;

  // Подмена метода Информация
  ФУНКЦИЯ СТРОКА: Информация
    // Для вызова метода предка используется 
    // ключевое слово РОДИТЕЛЬ
    РЕЗУЛЬТАТ = РОДИТЕЛЬ.Информация +
                ", сотрудник отдела " + отдел +
                " в должности " + должность 
  КОНЕЦ_ФУНКЦИИ
]

// Можно определить тип для указания конкретных начальных значений полей
ТИП Кладовщик(Сотрудник)
[
  // Не добавляем новых полей, а только устанавливаем 
  // начальные значения для унаследованных
  ПОДМЕНА отдел     = "склад";
  ПОДМЕНА должность = "кладовщик"; 
]

// Создадим объект типа Кладовщик
ВЫЧИСЛИТЬ
  // cоздаем переменную к типа Кладовщик
  ПЕРЕМ Кладовщик: к
  // присвоим некоторым полям значения
  к.фамилия  = "Иванова"
  к.имя      = "Мария"
  к.отчество = "Ивановна"
  к.дата_рождения = 12.06.1955
  
  // выводим информацию переменной к на экран
  СООБЩЕНИЕ(к.Информация)
  
  // При запуске программы в 2015 году мы увидим следующую строку:
  // "Иванова Мария Ивановна, возраст: 60 лет, сотрудник отдела склад в должности кладовщик".
  // Заметим, что значения полей отдел и должность остались равны начальным, 
  // определенным для типа Кладовщик.
  // При выводе информационной строки был вызван подмененный метод 
  // объектного типа Сотрудник.
КОНЕЦ

Использование ключевого слова САМ:

// объявляем тип Проводка
ТИП Проводка
[ 
  // объявляем поля
  СТРОКА: дебет, кредит;
  ЧИСЛО: сумма;

  // описываем метод сравнения с другой проводкой на равенство дебета и кредита
  ФУНКЦИЯ ЛОГИКА: РавныДК(Проводка: пр)
    // передаем в функцию СравнениеПроводок значения
    // текущего экземпляра типа Проводка в качестве первого параметра
    РЕЗУЛЬТАТ = СравнениеДК(САМ, пр)
  КОНЕЦ_ФУНКЦИИ
]

// функция сравнения дебета и кредита проводок
ФУНКЦИЯ ЛОГИКА: СравнениеДК(Проводка: пр1, пр2)
  РЕЗУЛЬТАТ = (пр1.дебет = пр2.дебет) И (пр1.кредит = пр2.кредит)
КОНЕЦ_ФУНКЦИИ

См. также: