Классы и библиотеки классов

Вы можете создать библиотеку, классы которой будут использоваться только внутри конкретного проекта приложения. Файл такой библиотеки удобно хранить в папке проекта. Вы так же можете создать библиотеку универсальных классов и поместить её в Галерею объектных компонентов Visual FoxPro (Component Gallery), сделав классы доступными для использования из множества приложений. В первом случае вы должны воспользоваться услугами Менеджера проектов, во втором — создать библиотеку вне проекта в диалоговом окне New.
Для создания новой библиотеки классов в Менеджере проектов выделите в нем узел Class Libraries и нажмите на кнопку New.
Альтернативные способы создания библиотеки классов:

  • В главном меню Visual FoxPro выберите пункт File, и затем, в появившемся меню, пункт New.

  • На панели инструментов Standard нажмите кнопку New.

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

Рис. 11.1. Окно New Class

В окне New Class:

  • в поле Class Name укажите имя создаваемого класса
  • в поле Based On укажите имя класса-родителя; это может быть как один из базовых классов Visual FoxPro, так и любой созданный вами класс, причём этот класс может располагаться как в этом, так и в любом другом библиотечном (или программном) файле
  • в поле Store In укажите полный путь и имя файла создаваемой библиотеки классов. При необходимости воспользуйтесь стандартным диалогом сохранения файла, который может быть вызван при нажатии на расположенную правее поля кнопку поиска.

Вы можете добавлять классы в уже существующую библиотеку. Для этого нужно просто открыть такую библиотеку для изменений, для чего в Менеджере проектов достаточно выделить узел с ее именем и нажать на кнопку New. Появится диалоговое окно New Class (рис. 11.1), в котором поле Store In уже будет содержать имя модифицируемой библиотеки. Альтернативный способ — открытие существующей библиотеки классов в меню File или при нажатии на кнопку Open в панели инструментов Standard.
Правее поля Based On располагается кнопка поиска, при нажатии на которую будет выведено специализированное диалоговое окно Open Конструктора классов (рис. 11.2). В отличие от стандартного диалогового окна Open, в этом окне вы можете выбрать в качестве родительского любой класс из любой библиотеки классов, и даже класс, объявленный в программном модуле (о программном создании классов будет рассказано в этой главе несколько позже).
В левой части окна выводится список папок и файлов. При установке указателя на строку с именем файла библиотеки классов в области Class Name окна появится список включенных в неё классов.
Выберите любой класс, отображаемый в области Class Name, и нажмите на кнопку Open. Выбранный класс будет использоваться как родительский для вашего класса.

Рис. 11.2. Окно Open Конструктора классов

Создание класса формы

Начнём изучение Конструктора классов с создания формы. Создайте проект, а в нем — библиотеку классов. Введите в поле Class Name окна New Class (рис. 11.1) имя нового класса, например, MyClassForm. Откройте список базовых классов Base On и выберите в нём строку Form. Назовите библиотеку, например, как MyClasses, после чего нажмите на кнопку OK. Visual FoxPro загрузит Конструктор классов (рис. 11.3).

Рис. 11.3. Окно Конструктора классов

Интерфейс Конструктора классов в целом аналогичен интерфейсу Конструктора форм. Он использует тот же набор инструментов и средств для визуального конструирования классов; основное отличие состоит в том, что в главном меню вместо пункта Form появился пункт Class. Обратите также внимание на информацию в окне Свойств (Properties): в строке Class вы видите имя, данное вами классу формы, а в строке ClassLibrary — имя библиотеки классов. Строка BaseClass идентифицирует базовый класс Visual FoxPro; как видите, созданный класс является производным от базового класса Form.
Присвойте свойству AutoCenter формы значение .T. (истина). Разместите на форме командную кнопку, в методе Click которой напишите следующий код:

 
 thisform.release
 

Закройте окно Конструктора классов.
Если вы создавали библиотеку классов из Менеджера проектов, то в результате ваших действий в узел Class Libraries будет добавлен новый вложенный узел, содержащий ссылку на созданную вами библиотеку классов; открыв этот узел, вы увидите в нём иконку только что созданной формы myclassform.

Рис. 11.4. Окно Менеджера проектов после добавления библиотеки классов

Создание объектов. Функции CREATEOBJECT() и NEWOBJECT()

Форму, созданную в Конструкторе форм, вы могли сразу запустить на выполнение, нажав на кнопку Run Менеджера проектов. Для формы, включенной в библиотеку классов, этого сделать нельзя. Следуя канонам объектно-ориентированного программирования, мы должны создать экземпляр класса — объект, для чего в Visual FoxPro применяются функции CREATEOBJECT() и NEWOBJECT().
Вот синтаксис объявления функции CREATEOBJECT():

 
 oObj = CREATEOBJECT(cClassName [, Parameters])
 

где:

  • cClassName — имя класса из библиотеки классов или процедурного файла

  • Parameters — перечисленные через запятую необязательные параметры, которые будут переданы в метод Init создаваемого объекта.

Функция возвращает ссылку (указатель) на созданный объект. Вы можете вызывать методы и устанавливать свойства объекта, используя следующий синтаксис:

 
 oObj.Method(Parameters)
 или
 oObj.Property = Value
 

В листинге 11.1 показано использование этой функции для создания объекта — экземпляра класса MyClassForm.

Листинг 11.1. Создание экземпляра класса MyClassForm функцией CREATEOBJECT()

 
 PUBLIC oForm
 cPath = JUSTPATH(SYS(16))
 SET DEFAULT TO (cPath)
 SET CLASSLIB TO MyClasses
 oForm = CREATEOBJECT('MyClassForm')
 oForm.Show()
 

Первые три строки кода предназначены для определения папки, используемой по умолчанию. Команда SET CLASSLIB указывает, что искать класс создаваемого объекта необходимо в библиотеке MyClasses.
Ссылка на созданный объект записывается в переменную oForm.
Последнее действие, выполняемое в коде листинга — это вызов метода Show созданной формы для ее отображения на экране.

Сохраните этот код в программном файле; этот файл должен находиться в той же папке, в которой находится файл библиотеки классов. Запустите его на выполнение. Форма появится на экране. Нажмите на кнопку — и форма закроется.

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

 
 SET CLASSLIB TO имя_файла_библиотеки_классов ADDITIVE
 

Удалить библиотеку классов из памяти можно командой

 
 RELEASE CLASSLIB имя_библиотеки_классов
 

Удалить из памяти все загруженные библиотеки можно командой SET CLASSLIB TO без параметров.

Функция NEWOBJECT(), в отличие от функции CREATEOBJECT(), не требует применения команды SET CLASSLIB; имя библиотеки классов передаётся ей как один из параметров:

 
 NEWOBJECT(cClassName [, cModule [, cInApplication [, Parameters]]])
 

где:

  • cClassName — имя класса из библиотеки классов или процедурного файла

  • cModule — необязательный параметр, определяющий имя файла (и, возможно, путь) библиотеки классов. Не используется, если необходимая библиотека загружена командой SET CLASSLIB.

  • cInApplication — определяет приложение Visual FoxPro (файл .exe или .app) содержащее .vcx файл, имя которого указано в cModule. Вы должны указать расширение файла приложения. cInApplication игнорируется, если параметр cModule опущен, или если значение cInApplication — пустая строка или ноль. Параметр cInApplication может использоваться только тогда, когда указан параметр cModule.

  • Parameters — перечисленные через запятую необязательные параметры, которые будут переданы в метод Init объекта.

В листинге 11.2 приведён код создания формы из класса MyClassForm при помощи функции NEWOBJECT().

Листинг 11.2. Создание экземпляра класса MyClassForm функцией NEWOBJECT()

 
 PUBLIC oForm
 cPath = JUSTPATH(SYS(16))
 SET DEFAULT TO (cPath)
 oForm = NEWOBJECT('MyClassForm', 'MyClasses')
 oForm.Show()
 

Полиморфизм в действии

Добавим в библиотеку классов ещё одну форму; в качестве родительского класса этой формы используем только что созданный класс MyClassForm.
Откройте библиотеку классов для изменения. В диалоговом окне New Class в поле Class Name введите имя нового класса, например, MyTwoForm. Нажмите на кнопку, расположенную правее поля Based On, в появившемся окне Open (см. рис. 11.2) найдите файл библиотеки классов MyClasses.vcx и выделите его. В области Class Name появится строка с именем класса MyClassForm. Выделите эту строку и нажмите на кнопку Open. После всех этих действий окно New Class должно выглядеть так, как показано на рис. 11.5.

Рис. 11.5. Окно New Class с пользовательским классом-родителем

Убедитесь, что в поле Based On действительно находится имя созданного вами ранее класса формы. Если всё правильно, то нажмите кнопку OK. Появится окно Конструктора классов, в котором вы увидите вашу форму, содержащую командную кнопку. Щелкните по этой кнопке, чтобы открылось окно для редактирования метода Click объекта. В этом окне ничего нет! Но ведь когда вы создавали форму MyClassForm, то записали в этот метод команду thisform.release! На самом деле код команды никуда не пропал: он инкапсулирован (скрыт) в дочернем классе. Найдите в окне Свойств строку для метода Click командной кнопки. Напротив имени метода вы увидите следующее:

 
 [Inherited MyClassForm имя_файла_библиотеки_классов]
 


То есть код этого метода унаследован он класса-родителя. А можно ли увидеть этот код? Да, можно. Для этого щелкните на кнопке View Parent Code, расположенной над областью ввода кода окна Редактора кода (рис. 11.6).

Рис. 11.6. Просмотр кода класса-родителя

В выпавшем списке выберите класс-родитель (этот список будет содержать имена всех предшествующих родительских классов). Откроется новое окно, в котором будет выведен код метода родительского класса. Вы не можете отредактировать этот код; но если вы всё-таки хотите его изменить, то откройте в Конструкторе классов соответствующий класс из иерархии родителей. Но при этом вы должны иметь ввиду, что изменение коснётся поведения всех классов, наследуемых от этого класса, и всех их потомков! То есть если код этого метода не изменён в одном из классов — потомков, то все объекты, созданные из этих классов, при вызове этого метода будут выполнять уже новый, изменённый вами, код метода класса — родителя.
Продолжим эксперимент. Закройте Конструктор классов и выполните код из листинга 11.1, изменив имя параметра функции CREATEOBJECT() с MyClassForm на MyTwoForm. На появившейся форме нажмите на кнопку. Выполнится код класса-родителя, и форма закроется. Это — следствие того, что в Visual FoxPro используется так называемое прямое (классическое) наследование, когда класс-наследник получает полный набор свойств и методов класса-родителя. Чтобы окончательно понять сущность полиморфизма, снова откройте класс MyTwoForm и введите новый код метода Click командной кнопки, вернее, введите в пустое окно редактора следующий код:

 
 = MESSAGEBOX('Код метода класса-родителя переопределён!')
 

Закройте Конструктор классов и запустите на выполнение модифицированный код из листинга 11.1. Нажмите на расположенную на форме кнопку. Что произошло? Форма не закрылась, но появилось стандартное диалоговое окно MESSAGEBOX (рис. 11.7):

Рис. 11.7. Полиморфизм в действии

Как видите, код метода класса-родителя теперь не выполняется; вместо него выполняется код метода дочернего класса. Это и есть проявление полиморфизма при наследовании. Если вы создадите ещё один класс, используя в качестве родителя класс MyTwoForm, то в этом дочернем классе будет унаследован метод Click кнопки, выводящий диалог с сообщением «Код метода класса-родителя переопределён»!
Но существует ли возможность при переопределении метода в дочернем классе выполнить код метода класса-родителя? Да, существует. Это — использование функции DODEFAULT(). Вызов этой функции в любом месте кода метода дочернего класса приводит к приостановке выполнения этого кода и выполнению кода метода класса-родителя. При вызове этой функции вы должны помнить о необходимости указать в ней все параметры, получаемые методом.
Изменим в последний раз код метода Click командной кнопки, используемой в классе MyTwoForm, добавив в него вызов функции DODEFAULT():

 
 = MESSAGEBOX('Код метода класса-родителя перегружен!')
 DODEFAULT()
 

Что получится в результате этого изменения? При нажатии на кнопку формы по-прежнему будет появляться диалоговое окно с сообщением, но после закрытия этого окна форма так же закроется — то есть выполнится метод Click кнопки класса — родителя MyClassForm.