.. Автор: Александр Орефков

.. include:: commonchm.txt

***************************************
Реализация ООП в 1С++
***************************************
..	<chminfo>
		<insert nodes="//common/maininfo/*"/>
		<alinks>_1cpp_oop_</alinks>
	</chminfo>

.. contents:: Содержание
	:backlinks: none

Введение
---------------
ООП - объектно-ориентированное программирование, является на сегодняшний день одной
из самых популярных технологий создания программных средств.
Данная разработка направлена на устранение недостатка отсутствия ООП в языке 1С.
Как известно, ООП базируется на трех основных принципах: полиморфизм, наследование
и инкапсуляция; в данной разработке для возможной технической реализации принципов,
были добавлены некоторые языковые средства.
Также добавлена возможность строгой проверки типов для параметров методов классов,
определяемых пользователем *(КОП)* и некоторые другие классы для расширения парадигмы ООП.

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

- уменьшение зависимостей не связанных между собой логически частей учетной системы; 
- уменьшение написания и тестирования кода для связанных между собой логически понятий
  объектов системы
- возможность расширения существующего функционала
- концентрирование кода алгоритма в одном программном модуле с четко определенным
  интерфейсом его использования, что позволит вносить изменения в алгоритм и осуществлять
  его исправление без необходимости проверки и исправления всего зависящего от него кода
- для разделения функционала на три логических уровня: уровень интерфейс пользователя,
  уровень бизнес-логики, уровень сохранения/получения (персистентность) результатов и
  объектов, другими словами - уровень взаимодействия с БД
- повторяемость кода или наследуемость кода базового класса его наследниками

В реализации наследования в ВК (внешней компоненте 1С:Предприятия) 1С++ необходимо
определить следующий функционал:

- Возможность наследования классов от встроенных типов, таких как: "Справочник", "Документ" и т.д.
- Возможность наследования от типов, определяемых пользователем (классов 1С++)
- Возможность вызова переопределенных функций производными классами из функций базового класса
- Возможность переопределения  функций базовых классов в классах наследниках
- Возможность вызова базовых функций из переопределенных функций наследуемого класса

**Полиморфизм** - заключается в переопределении поведения объекта с помощью  специализации
обобщенного класса, т.е. переопределение методов интерфейсов базового класса (общий класс)
его наследником (более специализированным классом). Полиморфизм позволит:

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

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

===========================
Работа с компонентой
===========================

Состав компоненты
---------------------------
- 1C:Предприятие 7.7, релиз, Windows98 OSR2, Windows 2000, Window XP
- Файл движка ООП для 1С 1C++.dll, подключается с помощью метода 1С \"ЗагрузитьВнешнююКомпоненту(Путь)\"
- Файл определения классов пользователя Defcls.prm, обязан находиться в каталоге информационной базы (ИБ)
  в которой используются классы, определяемые пользователем компоненты.
  Синтаксис языка определения классов см. ниже.
- Файл oxy.ini, который необходимо создать в каталоге BIN 1C:Предприятия для настройки псевдонимов
  путей к файлам реализации КОП.
- Файлы реализации классов могут быть как в текстовом формате, так и в формате отчетов с расширением \*.ert.
  Имена файлов и привязки файлов реализации к классам задаются в файле определения Defcls.prm.

Функционал класса
---------------------------
Каждый класс, определенный пользователем (КОП), создается в 1С с помощью метода СоздатьОбъект(ИмяКласса).

Для каждого КОП определен стандартный интерфейс, состоящий из следующих методов:

_`ПолучитьБазовыйКласс` (ИмяБазовогоКласса) / GetBaseClass(strNameOfBaseClass)
возвращает объект базового класса для класса предка, имя которого передается в качестве строки в параметр метода
\"ИмяБазовогоКласса\". Если объекта базового класса не существует, то метод возвратит 0.
Данный метод предназначен для вызова переопределенных методов базовых классов из методов
классов наследников и получения/установки атрибутов базовых классов.
Пример: имеются следующие справочники: \"Необоротные активы\", в котором содержатся общие
реквизиты всех необоротных активов предприятия, и справочники - спецификаторы, такие как
\"Основные средства\", \"Нематериальные активы\", которые, в свою очередь, добавляют
специфические реквизиты сущностей к общим реквизитам необоротных активов.
Исходя из описанной выше идеологии, мы строим следующую иерархию классов:
КОП с рабочим названием "ОС" наследует от классов 1С: справочника \"Необоротные активы\" и
\"Основные средства\" и переопределяет методы \"ВыбратьЭлементы()\" и \"ПолучитьЭлемент()\",
т.к у КОП \"ОС\" базовые классы имеют такие же методы, программист обязан разрешить
неоднозначность вызова, воспользовавшись в реализации методов \"ВыбратьЭлементы()\" и \"ПолучитьЭлемент()\"
класса \"ОС\" методом ПолучитьБазовыйКласс(\"Основные средства\") для вызова его функций
выборки и итераций и `ПолучитьБазовыйКласс`_ (\"Необоротные активы\") для проведения аналогичных операций.

_`НазначитьБазовыйКласс` (ИмяБазовогоКласса) / AssignBaseClass(NameOfBaseClass)
данный метод позволяет для созданного КОПа назначить динамически базовый класс в модуле,
где он используется. Что позволяет строить иерархию базовых классов, исходя из логики программы,
\"на лету\". Методом возможно создать иерархию глубиной всего в один уровень.

_`ОтправитьСообщениеМодулюХоз` (КтоОтправил, ВидСообщения, Данные)
/ SendMessageOwnMod(WhoSend, KindMessage, Data). Вызывает предопределенную функцию
ОбработкаСобытияОтКласса(отКого, стрСобытие, Данные) реализованную в модуле вызывающем работающий
в данный момент метод КОП, возвращает любое значение, которое будет получено после вызова
ОтправитьСообщениеМодулюХоз() в модуле КОП.

_`ПолучитьПуть` () / GetPathName(). Возвращает полный путь и название файла, в котором хранится
модуль реализации класса.

_`ПолучитьКонтекстОкружения` () / GetEnvContext() - Получить контекст окружения из модуля КОП.
Возврат: Возвращает контекст, из которого получил управление модуль КОП

_`ПолучитьСписокПараметров` (стрИмяМетода) / GetParamsList(strNameOfMeth)
Получить список со значениями неявных параметров, переданных в метод, название которого
необходимо передать в качестве параметра. Данный метод можно использовать только в теле
метода класса, который был определен с последним формальным параметром \":\" в файле
определения КОП. Более подробное описание см. в пункте 1.3., раздел \"Неопределенное количество параметров\".

_`УстановитьПараметрПоИндексу` (стрИмяМетода>,<чИнд>,<нЗнач) /
SetOnIndexParams(strNameOfMeth >,<nInd>,<uVal) - Метод предназначен для получения ссылки
значения неявного параметра по его порядковому номеру и установке нового значения по данной ссылке.
- стрИмяМетода - Имя метода ссылки на неявные параметры, которого необходимо получить.
- чИнд - номер неявного параметра, ссылку на который надо получить и заменить
- нЗнач - Новое значение.
Возврат: 1 - установка успешно произведена, 0 - произошла ошибка при установке

_`ЗаменитьЭксзБазовогоКласса` (стрИмяКласса>, <нЗначениеКласса) /
ReplaceInstBaseClasses(strNameClass>, <uValOfClass) - Предназначен для замены экземпляра
базового класса в уже созданной иерархии классов. Изменения базового класса отражаются только
на объекте, для которого был вызван данный метод.
- стрИмяКласса - имя базового класса, экземпляр которого мы собираемся заменять.
- нЗначениеКласса - новый экземпляр базового класса.
Возврат: 1- замена успешно произведена, 0 - произошла ошибка при замене

_`_ВыброситьИскл` (ОбъектИскл) / \_Throw(Object) - формирует исключение с объектом- исключением.
Вызов этого метода в модуле КОП прекращает его выполнение и данное исключение передается дальше
в другие модули для поиска обработчика исключения (раскрутка стека). Если такой обработчик
не будет найден, то выполнение последнего модуля будет прекращено с выводом диагностического
сообщения в окно сообщений 1С. Получить объект \"Исключение\" можно с помощью метода
GetExeption()/`ПолучитьИсключение <extobjs.chm::/extobjs31.html>`_ () дополнительного класса ExecuteModule/
`ВыполняемыйМодуль <extobjs.chm::/extobjs16.html>`_ .
ОбъектИскл - любой объект 1С.

_`_ПолучитьКод` () / _GetCode() - функция, которая должна вернуть строковое представление объекта;

_`_SQLCreate` (Value, obMDW) - процедура, которую должен реализовать КОП для типизации значения
поля выборки объекта ODBCRecordset типом этого КОП (виртуальный конструктор).
Должна быть объявлена в модуле с ключевым словом Экспорт. Должна иметь два или меньше параметров.
Её вызывает объект ODBCRecordset при получении значения поля выборки, при типизации типом этого КОП. 
Параметры:
- Value - значение поля выборки без типизации;
- obMDW - статический объект типа MetaDataWork.

Формат файла определения КОП
----------------------------

Файл определения классов должен быть расположен в одном каталоге с файлом конфигурации и
называться **Defcls.prm**, если файла с таким именем не обнаружено, ВК осуществляет поиск
в текущей конфигурации обработки с именем Defcls. Синтаксис языка определения классов следующий::

  // - комментарий для программы
  класс (class)  имя класса = имя файла класса реализации :
    <имя базового класса>, <имя базового класса> {
  Объявления методов класса
  };

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

**имя файла**
  <Путь>|<#Псевдоним>Имя файла.* | Имя обработки@MD файл реализации класса, если не указан путь,
  расположенный в каталоге с файлом конфигурации текущей ИБ, в котором реализуются методы класса
  и определяются атрибуты. Путь может быть относительным и формируется всегда относительно пути
  расположения конфигурации ИБ, вне зависимости от текущей папки файловой системы. Если указан
  #Псевдоним пути, то данный псевдоним ищется в файле инициализации компоненты, который должен
  находиться в каталоге BIN 1С:Предприятия и называться oxy.ini. В данном файле необходимо создать
  раздел [alias_path], который содержит все псевдонимы путей.

Текст КОП возможно хранить в конфигурации в виде обработок, для этого необходимо указать имя
обработки и прибавить окончание @MD, с соблюдением регистра букв у окончания.

Пример файла инициализации компоненты:: 

  [alias_path]
  Псевдоним1 = С:\Классы1С_1\
  Псевдоним2 = С:\Классы1С_2\

Далее в файле определения пути к классам необходимо написать следующее::

  класс МойКласс = #Псевдоним1\ Псевдоним1.ert {};

**имя базового класса**
  базовые классы класса **имя класса**. Базовые классы могут отсутствовать или их может быть несколько,
  тогда они разделяются запятой.
**объявление методов класса**
  функции и процедуры. Необязательно определять все функции, а только те, для которых необходимы
  проверка типов, определение  параметров по умолчанию, неявные параметры и передача параметров
  по значению. (все, что указано в угловых скобочках - опциональные элементы, без них -
  обязательные элементы)

функции:
  <Тип возвращаемого значения> Имя функции (Val | Знач> Тип 
  переменной <Имя переменной = Значение по умолчанию>, <Val | Знач> Тип 
  переменной <Имя переменной>, ...);

процедуры:
  void Имя процедуры (Val | Знач> Тип переменной Имя 
  переменной = Значение по умолчанию, <Val | Знач> Тип переменной <Имя 
  переменной>, ...);

Val | Знач
  предопределенное слово, означает, что параметр метода 
  передается по значению, т.е. в методе используется копия переданного параметра. 
  (необязательный)

Любой **тип** - может быть заменен ключевым словом Неопределенный 
(Undefine), что отключает для данного параметра\возвращаемого значения 
проверку типов. Типом может быть Справочник, что означает возможность 
передавать в параметр метода справичник любойго вида справочника, 
(аналогичное поведение для типов Документ, и Регистр, и т.п.) - смысл, 
аналогичный типу "Справочник" или ГрупповойКонтекст, когда типом параметра 
может быть контекст любого модуля. (обязательный)

Имя
  формального параметра метода. Обязательно должен быть указано при 
  определении значения по умолчанию, во всех остальных случаях - необязателено.
Значение по умолчанию
  задается после имени параметра и должно быть 
  одного того же типа, что и тип для данного параметра. Возможные типы: Строка 
  Пар1 = "Значение по умолчанию"; Число Пар1 = 100; Дата Пар1 = '01.01.2002', а 
  также КОП и агрегатные объекты 1С:Предприятия задаются с заключением их в 
  кавычки, например МойКласс ПарКласс = "МойКласс" - по умолчанию параметр 
  ПарКласс будет содержать в теле метода значение экземпляра класса "МойКласс". 
  Значением по умолчанию может быть простое выражение языка 1С, например - 
  значения констант, перечислений, функций без параметров. Например, Дата 
  дПарДата = РабочаяДата(), параметр "дПарДата" примет значение по умолчанию, 
  возвращенное из метода  РабочаяДата(). Внимание: при указании в качестве 
  значения по умолчанию "" - тип значения не учитывается. Значения по умолчанию 
  возможно задать только в последних параметрах метода.
Неопределенное количество параметров
  метод, объявленный с 
  параметром "...", может принимать любое количество параметров во время вызова. 
  Параметры метода, которые определены стандартным образом, называются 
  явными параметрами. Параметры, которые получены в ходе вызова метода в 
  месте определения троеточия и далее за ним, называются **неявными**. Пример: void 
  Метод1(Строка стрПар1, Число чПар2, ...);, где параметры стрПар1, чПар2 
  являются явными и при вызове метода в них обязательно необходимо передавать 
  значения их типов. Пример вызова данного метода может выглядеть так: 
  МойКласс.Метод1("{Пар3, Пар4, Пар5}", 200, "Значение параметра 3", "Значение 
  параметра 4", "Значение параметра 5"); , где значения неявных параметров равны 
  следующим строкам "Значение параметра 3", "Значение параметра 4", "Значение 
  параметра 5", количество таких значений в нашем примере равно 3, но оно может 
  быть любым и зависит только от потребностей алгоритма. И в то же время явные 
  параметры стрПар1 и чПар2 в нашем примере, соответственно, получат значения 
  "{Пар3, Пар4, Пар5}" и 200. В реализации метода "Метод1"  необходимо написать 
  процедуру со следующей сигнатурой: Процедура Метод(стрПар1, чПар2) //Тело 
  процедуры КонецПроцедуры. Значения неявных параметров можно получить 
  вызвав общий метод класса `ПолучитьСписокПараметров`_ (ИмяМетода) 
  (GetParamsList(NameOfMethod)), который возвращает список значений, 
  содержащий неявные значения параметров, переданных в метод. В одном из явных 
  параметров Вы можете передать строку, заключенную в фигурные скобки ({}), и 
  содержащую названия ключей, разделенных запятыми. Данные ключи 
  сопоставляются с неявными параметрами в списке значений, которые в реализации 
  метода класса можно получить, использовав метод списка "Получить(Строка)". В 
  нашем примере таким строковым (явным) параметром является первый параметр 
  метода "стрПар1", значение которого при вызове метода равно "{Пар3, Пар4, 
  Пар5}", что означает - в списке значений неявных параметров содержатся 
  значения "Значение параметра 3", строковый ключ которого равен "Пар3", 
  следующее значение "Значение параметра 4", а ключ для него "Пар4" и т.д.

Примеры::

  класс Базовый_1=Base_1.txt
  {
    void Метод1(Число пар1, Строка пар2);
    Число Метод2(Число пар1, Дата пар2);
  };
  класс Производный_1=Derive_1.txt: Базовый_1, Справочник.Спр1, ТаблицаЗначений
  {
    void Метод1(Число пар1, Строка пар2); // Данный метод переопределяет метод 
      //базового класса
    Число КоличествоСтрок (Число Колич); // В данном случае мы переопределили 
      //метод базового класса ТаблицаЗначений и добавили проверку типов. В реализации этого 
      //метода можно переадресовать вызов базовому классу
    void Метод3(ОС ОС); // в этот метод мы должны передаем передавать КОП "ОС"
  };
  класс ОС=OC.txt : Справочник.ОсновныеСредства, Справочник.НематериальныеАктивы
  {
    void Метод1(Базовый_1 пар1); // В данном случае в пар1 можно передавать 
      //объекты типа "Базовый_1" и его производный класс "Производный_1"
    void Метод2(Производный_1 пар1); // в отличие от предыдущего случае в пар1 мы 
      //можем передавать объекты типа "Производный_1", но не "Базовый_1"
    Число ВыбратьЭлементы(Число чРежим);
    Число ПолучитьЭлемент(Число чРежим);
  };

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

Формат файлов реализации КОП
----------------------------

Для каждого КОП необходим отдельный файл реализации (как текстовый, так 
и отчет 1С), расположенный в каталоге БД или в папке, указанной в определении имени 
файла класса, либо в папке, указанной в псевдониме пути. С именем класса связывается 
файл реализации КОП в файле определения Defcls.prm.

Синтаксис языка файла реализации КОП полностью соответствует 
синтаксису языка 1С:Предприятия, плюс возможно использовать препроцессорные 
директивы.

Открытые атрибуты КОП определяются как общие переменные в модуле с 
ключевым словом *Экспорт*.

Закрытые атрибуты КОП определяются как общие переменные в модуле без 
ключевого слова *Экспорт*.
      
Обращение к методам компоненты из файла реализации КОП (модуля 
КОП), таких таким как: `ПолучитьБазовыйКласс`_ и `НазначитьБазовыйКласс`_, 
осуществляется через Контекст данного модуля. Пример::

	// В начале каждого модуля определяем закрытую функцию для получения
	// контекста.
	Функция GetThis(Конт) Возврат Конт; КонецФункции

	// Реализация метода "Метод1" класса "Производный_1" см. предыдущий пример
	Процедура Метод1 (пар1, пар2) Экспорт
		Конт = GetThis(Контекст);
		Базовый_1 = Конт.ПолучитьБазовыйКласс("Базовый_1");
		Если Базовый_1 <> 0 Тогда

		КонецЕсли; 
	КонецПроцедуры
	
.. Attention:: Предупреждение: нельзя сохранять контекст класса в его 
   атрибуте, т.е. запрещен следующий алгоритм::

     Перем Конт;
     Функция GetThis(Конт) Возврат Конт; КонецФункции
     ...............
     Конт = GetThis(Контекст);
     ...............

   Если Вы будете использовать такое присваивание, объекты класса, созданные Вами 
   в алгоритмах с помощью конструкции СоздатьОбъект("ИмяКлассаКОП"), никогда 
   не уничтожатся (memory leaks), из-за циклической ссылки на объект внутри модуля 
   реализации КОП. Это замечание также справедливо и для взаимных ссылок, когда 
   один экземпляр класса содержит в себе ссылку на другой, и этот другой, в свою 
   очередь, имеет ссылку на первый.

В каждой реализации класса можно создать процедуры **Конструктор** () англ. 
Constructor() и **Деструктор** () англ. Destructor(), которые вызываются, соответственно, в 
моменты создания экземпляра класса и его уничтожения (Конструктор() - объект создан, 
Деструктор() - объект уничтожен). Реализация данных процедур не обязательна.

Для контроля установки/записи атрибутов необходимо определить 
предопределенные методы (Процедура) в модуле реализации КОП (слово Экспорт к 
данным методам применять не обязательно):

- При чтении атрибута класса вызывается метод 
  **ПриПолучении_ИмяАтрибута** (ЗначениеАтрибута) англ. OnGet\_, где 
  ИмяАтрибута - имя атрибута, определенного в модуле КОП, из которого 
  выполняют считывание, ЗначениеАтрибута - текущее значение атрибута, 
  также сам атрибут доступен из кода данного метода. Данный метод не 
  изменяет состояние самого атрибута по умолчанию.
- При записи в атрибут класса вызывается метод 
  **ПриЗаписи_ИмяАтрибута** (ЗначениеДляУст) англ. OnWrite\_, где 
  ИмяАтрибута - имя атрибута, определенного в модуле КОП, для которого 
  устанавливают значение, передаваемое в параметре ЗначениеДляУст. 
  Атрибут доступен в коде данного метода, и для его установки необходимо 
  присвоить атрибуту полученный параметр метода. Данный метод не 
  изменяет состояние самого атрибута по умолчанию.
- Динамические атрибуты класса реализуются посредством написания 
  предопределенных методов класса: 

  - При чтении динамического атрибута класса вызывается 
    предопределенная функция **\_ПриЧтенииСвойства** (стрИмяАтрибута) англ. 
    _OnReadProperty(strNameOfAttr) в параметр "стрИмяАтрибута" 
    передается название атрибута, как оно было указано в вызывающем 
    коде. Возвращать данный метод обязан значение считанного 
    атрибута с названием, полученным из параметра метода 
    "стрИмяАтрибута".
  - При установке значения атрибута экземпляра класса вызывается 
    предопределенная процедура 
    **\_ПриЗаписиСвойства** (стрИмяАтрибута,  НовоеЗначениеАтриб), 
    где "стрИмяАтрибута" - имя записываемого свойства, а в 
    параметре "НовоеЗначениеАтриб" содержится новое значение 
    атрибута, т.е. правая часть выражения присваивания нового значения 
    свойству класса.

**Отладчик**: Для получения информации в отладчике по динамическим 
свойствам класса необходимо определить следующие функции:

1. _GetNDynamicProps() / **\_ПолучитьКолвоДСвойств** - 
   возвращает количество динамических свойств.
#. _GetPropDynamicName(nNPar) / **\_ПолучитьИмяДСвойства** (чНомерПар) - должна возвратить 
   имя по номеру динамического свойства, номер лежит в 
   пределах от 1 до _GetNDynamicProps() включительно.

.. Attention:: Методы обязательно должны реализоваться оба, нельзя 
  реализовать только один из них. Если Вы определили данные методы, то 
  отключаются автоматическая установка/чтение статических атрибутов 
  класса и не вызываются определенные методы обработки  установки/чтения 
  "ПриЗаписи_ИмяАтрибута" и "ПриПолучении_ИмяАтрибута".  
  Вся обработка по сохранению/возврату значений атрибутов (свойств) 
  ложится на разработчика класса.

В базовых классах иерархии возможно вызывать открытые методы 
производных классов (объявленные с ключевым словом "Экспорт"), 
воспользовавшись для этого контекстом модуля базового класса, также с помощью 
контекста возможно получить название конечного созданного класса (с помощью 
функции "СоздатьОбъект"). 

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

1. IsSerializable() рус. **КлассСохраняемый** () /Функция/, метод должен 
   возвращать 1, если класс может быть восстановлен или записан в строку.
#. SaveToString() рус. **СохранитьКлассВСтроку** () /Функция/, метод должен 
   возвращать строку, по которой потом можно будет восстановить состояние 
   экземпляра класса. Реализация данной функции производится создателем 
   класса.
#. LoadFromString(str) рус. **ЗагрузитьИзСтроки** (стр) /Процедура/, в данный 
   метод передается строка ранее полученная из метода 
   "СохранитьКлассВСтроку()", по которой можно восстановить состояние 
   класса, существовавшее на момент сохранения. Данный метод необходимо 
   реализовать с модификатором доступа "Экспорт".

Если в классе реализован метод "КлассСохраняемый()", который возвращает 
значение, не равное 0, и реализован метод СохранитьКлассВСтроку(), то при 
использовании функции 1С ЗначениеВСтрокуВнутр(ЭкзКласса) вернет строку, 
сформированную в классе "ЭкзКласса" методом "СохранитьКлассВСтроку()". 

.. Attention:: Для восстановления классов КОП, поддерживающих сериализацию, 
  необходимо напрямую вызывать его метод "ЗагрузитьИзСтроки()", функция 1С 
  "ЗначениеИзСтрокиВнутр" не может создавать экземпляры классов КОП. 
  Поэтому можно реализовать вспомогательную функцию, которая бы создавала 
  экз. классов КОП и вызывала их метод десериализации. Код может быть 
  следующим::

    Функция глКлассИзСтрокиВнутр(стрЗнач) Экспорт
        сз = СоздатьОбъект("СписокЗначений");
        сз.ИзСтрокиСРазделителями(стрЗнач);
        Если сз.РазмерСписка() > 0 Тогда
            стрНазваниеКласса = сз.ПолучитьЗначение(1);
            Если ПустоеЗначение(стрНазваниеКласса)=1 Тогда
              Возврат -2;
            КонецЕсли;  
            Попытка
                о = СоздатьОбъект(стрНазваниеКласса);
                бКлассСохр = 0;
                Попытка
                    бКлассСохр = о.IsSerializable();
                Исключение
                    Попытка
                        бКлассСохр = о.КлассСохраняемый();
                    Исключение
                        Возврат -4;
                    КонецПопытки;   
                КонецПопытки;
                Если бКлассСохр = 0 Тогда
                  Возврат -4;
                КонецЕсли;                      
                Попытка
                    о.LoadFromString(сз.ВСтрокуСРазделителями());
                Исключение
                    Попытка
                      о.ЗагрузитьИзСтроки(сз.ВСтрокуСРазделителями());
                    Исключение
                        Возврат -5;
                    КонецПопытки;
                КонецПопытки;
                Возврат о;
            Исключение
                Возврат -3;
            КонецПопытки;
        Иначе
            Возврат -1;
        КонецЕсли;
    КонецФункции //глКлассИзСтрокиВнутр

.. Note:: Автоматическое групповое сохранение и восстановление 
  экземпляров классов, возможно, выполнять с помощью класса "DynaValue" (см. 
  глава 3.6., описание методов "ВыгрузитьВСтроку", "ЗагрузитьИзСтроки", 
  "ВыгрузитьВФайл", "ЗагрузитьИзФайла")

Примеры:
Иерархия классов выглядит так::

	class База = base.ert
	{
		void Метод1(); // Этот метод мы не переопределяем, а вызываем здесь 
										  // Метод2 производного класса
		void Метод2();	
	};    
	class Производный = derive.ert : Тест14_База
	{
		void Метод2(); // переопределяем метод базового класса
	};  

Модуль реализации класса "База"::

	Функция GetThis(Конт) Возврат Конт; КонецФункции 

	Процедура Метод2() Экспорт
		Сообщить("База::Метод2"); 
	КонецПроцедуры
	Процедура Метод1() Экспорт
		Сообщить("ТипзначенияСтр(Контекст) = 
	"+ТипзначенияСтр(GetThis(Контекст))); // получаем название текущего класса
		GetThis(Контекст).Метод2(); // вызываем переопределенный метод 
	КонецПроцедуры

Модуль реализации класса "Производный"::

	Процедура Метод2() Экспорт
		Сообщить("Производный::Метод2");  
	КонецПроцедуры
	
Модуль::

      Сообщить("Создали Производный класс");
      копПрозв = СоздатьОбъект("Производный");
      копПрозв. Метод1();
      Сообщить("Создали База класс");
      копБаза = СоздатьОбъект("База");
      копБаза. Метод1();
      
Вывод на экран будет следующим::

	Создали Производный класс
	Производный
	Производный::Метод2 
	Создали База класс
	База
	База::Метод2

В одном модуле можно хранить код нескольких классов. Для этого 
необходимо код каждого класса заключить в следующие скобки::

	//# ClassBegin <ClassName1>;
	Перем ПеременнаяКласса1;
	Процедура Конструктор()
		.........
	//# ClassEnd <ClassName1>;



	//# ClassBegin <ClassName2>;
	Перем ПеременнаяКласса2;
	Процедура Конструктор()
		.........
	//# ClassEnd <ClassName2>;

Где вместо <ClassName1> нужно указать имя класса (без угловых скобок).
Ограничения:

- Текст одного класса обязательно должен идти одним куском.
- Штатный синтаксис-контроль подобных модулей не работает.
- Формирование ALS-файлов для таких классов - невозможно.

Препроцессор
------------

Директивы препроцессора 1С++ могут быть в файлах объявления интерфейсов классов 
(Defcls.prm), в файлах реализации КОП и во всех модулях 1С, кроме модуля глобального 
модуля и модулей внешних обработок/отчетов. Символы препроцессора, объявленные в 
файле объявления класса, действительны в области видимости модулей реализации 
класса, т.е. доступны в файлах реализации КОП. Внимание: из-за раздельной 
интерпретации файла Defcls.prm и файлов реализации КОП изменения, определения и 
отключение символов препроцессора осуществляются независимо. Работа препроцессора 
гарантируется в следующей последовательности: сначала обрабатывается файл 
Defcls.prm, затем в неопределенной последовательности обрабатываются файлы 
реализации КОП.

.. Attention: Все директивы препроцессора должны начинаться с новой 
  строки и тело ее не должно переноситься на следующую строку.

//#if symbol [operator symbol]
  Если символ определен, что равнозначно "истине", 
  или символы, объединённые логическими операторами дают в результате 
  "истину", то код, заключенный между директивами //#if  и //#elif  или  //#else или  
  //#endif, буден включен на выполнение.  
  Symbol - это символ, который будет тестироваться на определенность ранее 
  директивой //#define. Перед символом можно использовать знак ! (логическое 
  отрицание).  
  Operator:: 

    =  (равно); 
    !=  (не равно); 
    &   (И); 
    \|   (ИЛИ);

  тело с кодом, открытое директивой //#if, должно закрываться директивами //#elif , 
  //#else, //#endif;
//#else
  директива, тело которой получает управление, если выражение равно 
  "ложь" в предшествующих ей директивах //#if или //#elif. Тело с кодом должно 
  заканчиваться директивой //#endif;
//#elif symbol [operator symbol]
  директива, управление на которую передается, 
  если в предыдущих директивах //#elif и //#if была получена "ложь". Проверяются 
  условия указанные symbol [operator symbol]... и, если получена "истина", код 
  заключенный в блоке между //#elif, и следующим за ним директивой //#elif или 
  #else или //#endif, включается в код модуля КОП. Описание symbol [operator 
  symbol]... см. у директивы //#if;
//#define symbol
  определяет символ условной компиляции, использование этого 
  символа в условных директивах даст "истину", с условием отсутствия снятия этого 
  символа ранее директивой //#undef;
//#undef symbol
  убирает определенный ранее символ. Символ используется для 
  условной интерпретации  кода в директивах //#if, //#elif, //#else;
//#warning text
  выводит "text" в окно сообщений 1С. Примечание: в Defcls.prm 
  данная директива отключена;
//#error text
  останавливает выполнение кода программы в этом месте с выводом 
  "text" в окно сообщений 1С. Примечание: в Defcls.prm данная директива 
  отключена;
//#preprocessor off
  данная директива должна располагаться в первой строке 
  модуля и служит для выключения препроцессорной обработки кода модуля.
//#exinfo
  данная директива может быть использована только в модулях 
  реализации КОП. Директива выводит информацию пользователю о месте вызова 
  метода, в котором она расположена, и строку кода, который осуществил вызов 
  метода. В основном используется в отладочных целях.
#include "<#alias></pathname/>namefile.ext"
  директива служит для вкладывания 
  других файлов определений в основной файл проекта (ИБ) defcls.prm. В пути к 
  файлу может быть использован псевдоним, определенный в oxy.ini, относительный 
  путь или полный путь к файлу. Каталогом по умолчанию считается каталог ИБ. 
  Расширение файла может быть txt, prm - обычные текстовые файлы и ert - модуль 
  отчета 1С
#curmeth
  директива выводит на экран текущий исполняемый метод класса и его 
  параметры с актуальными значениями и типами в месте появления данной 
  директивы. Примечание: в Defcls.prm данная директива отключена.

Отладка классов 1C++
--------------------

Для отладки модулей классов необходимо выполнить следующие действия:

1. Если модуль класса расположен в текстовом файле, то следует сохранить 
   его в модуле отчета;
2. Форма отчета, в котором хранится модуль класса, обязана иметь хотя бы 
   один диалоговый элемент.
3. В настройках компоненты 1С++ нажать кнопку "Отладка;

.. Attention: Не допускается использование функции СтатусВозврата(0) и 
  или Форма.Закрыть() в теле процедуры "ПриОткрытии()"
.. Attention: Рекомендуется в клиентском режиме 1С:Предприятия выключать 
  режим "Отладки".
.. Attention: Для отладки классов, разработанных в ранних версиях 1С++, вам
  может потребоваться удалить строку в процедуре ПриОткрытии()
     Форма.Параметр._ПриОткрытии();
  Либо прописать в глобальном модуле конфигурации экспортную переменную 
     Перем Форма Экспорт;

Настройка 1C++
--------------

Настройка компоненты осуществляется с помощью настройки параметров 1С, 
Сервис --> Параметры ... --> Закладка "Настройка 1C++". Данная закладка появляется 
только после загрузки компоненты методом 1С ЗагрузитьВнешнююКомпоненту.

На данной закладке присутствуют три флажка в виде кнопок: "Проверка типов" и 
"Оптимизация", "Отладка":

- **Проверка** типов включает строгую проверку типов во время выполнения 
  кода, при этом несколько увеличивается время вызова метода, в финальной 
  версии программного продукта рекомендуется отключать данную опцию;
- **Оптимизация** представляет собой метод "отложенных вычислений", 
  который реализован в следующем виде: если в системе не разу не 
  инстанцировался (создавался экземпляр КОП) класс, то его реализация 
  (модуль КОП) не считывается с диска и не компилируется в P-код. При 
  первом создании объекта КОП происходит считывание с диска модуля и его 
  компиляция, далее откомпилированный модуль сохраняется в репозитории 
  модулей КОП, и в последующих созданиях объектов этапы по считыванию с 
  диска и компиляции не производятся. Данная оптимизация позволяет 
  существенно уменьшить время создания объектов КОП, за счет увеличения 
  объёма используемой памяти компьютера, что несущественно для данного 
  вида оптимизации. Это режим рекомендуется включать в финальной версии 
  продукта. При отключенной оптимизации при каждом создании объекта 
  происходит считывание с диска и компиляция модуля КОП, что позволяет 
  вносить изменения в модуль без закрытия/открытия 1С в режиме 
  1С:Предприятие. По аналогии с #LoadFromFile для модулей 1С.
- **Отладка** позволяет отлаживать в отладчике 1С модули классов, которые 
  хранятся в модулях отчетов. В финальной версии программного продукта 
  **необходимо** отключать данную опцию.
