
- •Основы офисного программирования и язык vba
- •Офисное программирование
- •Состав Office 2000
- •Инсталляция Office 2000
- •Содержимое диска "Resource Kit"
- •Документ Issues
- •Документ ork9
- •Папка Tools
- •Содержимое диска "Language Pack"
- •Об этой книге и ...
- •Моя благодарность
- •Vba и объекты. Обзор
- •Библиотека объектов Office 2000 - каркас приложений
- •Встраивание вместо наследования
- •Построение каркаса документа
- •Библиотека объектов Office 2000 и Object Browser
- •Объекты Application
- •Свойства-участники
- •Вторая группа терминальных свойств
- •Методы объектов Application
- •События объектов Application
- •Совместная работа приложений. Создание объектов Application. Раннее и позднее связывание
- •Коллекции в Office 2000
- •Коллекции объектов Office 2000
- •Коллекции Excel: Workbooks, Sheets
- •Коллекция Workbooks
- •Коллекция Sheets
- •Коллекции Word: Documents, Paragraphs и другие
- •Коллекция Documents
- •Коллекция Paragraphs
- •Коллекция Sections
- •Коллекции Characters, Words, Sentences
- •Коллекции и конструкция For Each … Next
- •Объекты Range
- •Что определяет объект Range?
- •Метод Range
- •Объекты Selection
- •Метод Select и свойство Selection
- •Активные объекты и метод Activate
- •Проектирование документов
- •Документ и его программный проект
- •Модули - обработчики событий
- •Стандартные модули
- •Модули классов
- •Модуль макросов
- •Структура модуля. Окно проекта и Окно кода
- •Окно проекта
- •Свойства проекта
- •Имя проекта
- •Защита проекта
- •Окно кода
- •Еще раз о "переиспользовании" модулей
- •Проект и область видимости
- •Система документов и ее проект
- •Организация системы документов
- •Как организуются ссылки между проектами
- •Обмен информацией между документами
- •Система документов One - Two - Three
- •Типы данных
- •Простые типы данных.
- •Объявление переменных и констант простых типов
- •Синтаксис объявления простых переменных
- •Объявления по умолчанию
- •Константы
- •Массивы
- •Динамические массивы
- •Записи и тип, определенный программистом
- •Что можно делать с записями?
- •Раздел объявлений
- •Раздел опций
- •Разделы констант, типов и переменных
- •Раздел Declare
- •Правила именования
- •Типы и классы Еще раз о понятии "класс"
- •Что нового в классах "Office 2000"
- •Создание класса "Личность"
- •Объекты и переменные
- •Объекты, класс которых определен пользователем.
- •Объекты "родного" приложения
- •ActiveX-объекты
- •Модуль класса Свойства
- •Сокрытие свойств
- •Конструкторы и деструкторы. Стандартные события
- •Стандартные события Initialize и Terminate
- •Два конструктора класса Rational
- •Процедуры - свойства
- •Как создаются процедуры- свойства
- •Синтаксис Let, Get и Set
- •Классы, как упаковка
- •Семейство классов и процедуры - свойства
- •Friend методы
- •События
- •Классы, объекты With Events и обработчики событий
- •Модуль класса с объектом WithEvents
- •Объект WithEvents
- •События собственных классов
- •Как создать класс с событиями
- •Как зажигаются события
- •Где и как следует создавать обработчики событий для экземпляров класса
- •Связывание объектов
- •Реальные объекты и инициирование событий
- •Семейство классов и реализация интерфейсов
- •Наследование
- •Виртуальные методы и полиморфизм
- •Абстрактные классы
- •Наследование и полиморфизм в Office 2000
- •Наследование интерфейсов
- •Полиморфизм семейства классов
- •Проект "Люди и Машины"
Абстрактные классы
Виртуальный метод называется чистым, если в классе не определена его реализация. Класс называется абстрактным, если в нем объявлен один или более чистых методов. Из этого определения следует, что абстрактный класс не полностью определен, и потому работать с объектами абстрактного класса невозможно. Это, конечно, не означает, что нельзя объявлять объекты такого класса, это делать можно и нужно. Вся прелесть в том и состоит, что, перед тем как начать работать с таким родительским объектом, он связывается с одним из своих потомков - объектом, класс которого определен полностью. Абстрактные классы - важный механизм создания семейства классов. Как правило, абстрактные классы выступают в роли прародителей семейства классов, в котором многие классы имеют подобные свойства и поведение, отличаясь рядом деталей. Абстрактный класс позволяет задать общий интерфейс семейства, предопределяя, что все потомки должны уметь реагировать на вызов общих методов, хотя эта реакция может быть и разной. Благодаря свойствам, определенных абстрактным классом, все потомки позволяют задавать значения некоторых общих свойств. Итак, назначение абстрактного класса в том, что он задает общие свойства и общие виртуальные методы, которыми должны обладать его потомки. Именно потомки будут определять реализацию чистых виртуальных методов. Но эти методы предусмотрены и запроектированы на самом верхнем уровне.
Наследование и полиморфизм в Office 2000
В двух предыдущих пунктах мы рассмотрели довольно бегло общие понятия наследования и полиморфизма. Теперь же попробуем понять, как эти понятия реализованы в Office 2000. Прежде всего, заметим, что полиморфизм семейства классов реализован в полном объеме, а наследование, как ни странно, лишь частично. Начнем наше рассмотрение с наследования интерфейсов.
Наследование интерфейсов
В Office 2000 на классах введено отношение "наследование интерфейса" . Здесь под интерфейсом понимается совокупность всех открытых (Public) свойств и методов класса. Пусть уже создан класс A, который будем называть родительским или базовым. Тогда при создании нового класса B, который будем называть классом-потомком, можно объявить, что потомок наследует интерфейс родительского класса. Заметьте, что это отношение в отличие от "классического" наследования не транзитивно, - потомок класса B не наследует интерфейс класса A - родителя класса B. Однако допускается множественное наследование интерфейсов, потомок может иметь несколько родителей, - наследовать интерфейсы нескольких классов. Говоря о родительском классе, следует отметить три возможности:
-
Родительский класс может быть полностью абстрактным классом, то есть все его открытые методы будут чистыми, не имеющими реализации.
-
Родительский класс может быть полностью определенным классом с заданной реализацией методов.
-
Зачастую, родительский класс является абстрактным классом, где часть методов, реализация которых предполагается одинаковой для большинства классов - потомков, задана, а некоторые методы являются чистыми.
Синтаксически, объявить о том, что класс наследует интерфейс другого класса, достаточно просто. Для этого достаточно в объявление класса поместить одну строчку:
Implements имя_родительского_класса
При появлении такой строки класс- потомок наследует интерфейс родительского класса. Это означает, что будут наследоваться все открытые методы, а для каждого открытого свойства, будет наследоваться пара процедур - свойств Property Get и Property Let. Сами свойства наследоваться не будут. Как только в раздел объявлений класса вставлена строка "Implements", в окне кода этого класса появится список методов родительского класса, реализацию которых предстоит написать. Для того чтобы задать реализацию этих методов, используется привычная техника первоначального создания заготовок методов с последующим наполнением их содержательным текстом.
Важно понимать, что наследование интерфейсов не означает наследование реализации методов. Это просто некоторый контракт между родителем и потомком. Потомок обязуется реализовать все открытые методы своего родителя, а для открытых свойств соответствующие процедуры - свойства. Заметьте, реализованы должны быть все методы, хотя реализация может быть фиктивной и свестись к заданию некоторого комментария.
Если соответствующий метод родительского класса является чистым, то понятно, что потомок обязан дать собственную реализацию метода. Собственная реализация необходима и в том случае, если потомок хочет переопределить существующий метод родителя. Во многих случаях хотелось бы просто наследовать метод родителя, но, заметьте, автоматически это не делается. Здесь есть две возможности:
-
Использовать обычную схему Copy - Paste, копируя реализацию родителя.
-
Реализовать наследование типичным для Office 2000 способом путем встраивания родительского объекта в класс - потомок. Тогда можно вызывать в нужном месте нужный метод родителя. Чуть позже мы рассмотрим проект "Люди и машины", где используем этот прием.
Еще одна важная особенность наследования интерфейса состоит в том, что интерфейс родителя не становится интерфейсом потомка. Как следствие этого факта, отсутствие транзитивности отношения "наследование интерфейсов". Синтаксически, это определяется двумя обстоятельствами:
-
Заготовки методов, строящиеся автоматически, используют спецификатор Private. Это означает, что наследуемые методы не являются открытыми методами потомка и, следовательно, не входят в его интерфейс и не передаются далее внукам родителя.
-
Еще одна особенность состоит в том, что имена наследуемых методов содержат имя родителя. Это также означает, что наследуемый метод не становится собственным методом, который можно передать далее своим потомкам
Возникает естественный вопрос, если наследуемые методы не входят в интерфейс класса, а следовательно не могут быть вызваны объектами данного класса, то какой в них толк? Толк есть, поскольку эти методы могут быть все-таки вызваны объектами, правда, принадлежащими родительскому классу. Объект родительского класса, ссылающийся на своего потомка, может вызывать методы родителя, наследуемые потомком. Вот небольшой пример, где действую объекты трех классов Father, Son и GrandSon, связанные отношением наследования интерфейсов. Пусть определен абстрактный класс Father, интерфейс которого состоит из одного свойства, одного чистого метода и метода с заданной реализацией:
'Class Father
'Свойства класса
Public MyProperty As String
'Методы класса
Public Sub MyPureMethod()
'Чистый метод
End Sub
Public Sub MyRealMethod()
MsgBox ("It's the Father")
End Sub
Класс Son, наследующий интерфейс класса Father, по контракту должен реализовать две процедуры - свойства и два его метода. Мы дали только формальную реализацию, - в созданные автоматически заготовки добавили комментарии. Лишь в реализацию метода Father_MyPureMethod класса Son вставлена строка текста. Кроме того, в класс добавлен новый метод, определяющий собственный интерфейс этого класса. Вот описание этого класса:
'Класс Son - Наследник класса Father
Implements Father
Private Property Let Father_MyProperty(ByVal RHS As String)
'Реализация отложена
End Property
Private Property Get Father_MyProperty() As String
'Реализация отложена
End Property
Private Sub Father_MyPureMethod()
MsgBox ("It's the Son")
End Sub
Private Sub Father_MyRealMethod()
'Реализация отложена
End Sub
Public Sub SonNewMethod()
MsgBox ("It's the Son of his Father")
End Sub
Пример 5.1. (html, txt)
Заметьте, что, конечно, можно в наследуемых методах изменить спецификатор Private на Public, и тогда эти методы войдут в интерфейс класса - потомка. Но лучше этого не делать, хотя бы потому, что наследование таких методов приведет к ошибке, - наследование наследуемых методов не допускается, как мы уже говорили. Правильный путь состоит в создании собственных Public методов, в которых при необходимости вызываются Private методы.
Приведем теперь описание класса GrandSon - потомка классов Son и Father. Заметьте, класс явно определяет обоих своих родителей. Опять-таки мы ограничились формальной реализацией, определив лишь реализацию метода Father_MyRealMethod:
Option Explicit
Implements Father
Implements Son
Private Property Let Father_MyProperty(ByVal RHS As String)
'Реализация отложена
End Property
Private Property Get Father_MyProperty() As String
'Реализация отложена
End Property
Private Sub Father_MyPureMethod()
'Реализация отложена
End Sub
Private Sub Father_MyRealMethod()
'Реализация отложена
MsgBox ("It's the GrandSon")
End Sub
Private Sub Son_SonNewMethod()
'Реализация отложена
End Sub
Пример 5.2. (html, txt)
Приведем теперь пример процедуры из стандартного модуля, где действуют объекты всех трех классов семейства:
Public Sub Family()
Dim F As New Father, S As New Son, GS As New GrandSon
Dim Grand As Father, GrandS As Son
Set Grand = F
Grand.MyProperty = "Flat"
Grand.MyRealMethod
Grand.MyPureMethod
Debug.Print Grand.MyProperty
Set Grand = S
Grand.MyProperty = "Flat"
Grand.MyRealMethod
Grand.MyPureMethod
If TypeOf Grand Is Son Then
Set GrandS = Grand: GrandS.SonNewMethod
End If
Debug.Print Grand.MyProperty
Set Grand = GS
If TypeOf Grand Is GrandSon Then
Set GrandS = Grand: GrandS.SonNewMethod
End If
Grand.MyProperty = "Flat"
Grand.MyRealMethod
Grand.MyPureMethod
Debug.Print Grand.MyProperty
End Sub
Пример 5.3. (html, txt)
В этом примере объект Grand класса Father связывается поочередно с объектами класса Father, Son, GrandSon и всякий раз вызываются методы родительского класса, унаследованные потомками. Обратите внимание на конструкцию TypeOf - Is, позволяющую определить текущий тип объекта. В процессе работы этой процедуры будут открываться диалоговые окна, уведомляющие, что мы встретились с объектами Father, Son, Son of his Father, GrandSon. При печати свойств лишь однажды будет напечатано значение Flat.
Уже этот пример показывает, что наследование интерфейсов мало что дает с точки зрения наследования свойств и методов, поскольку ни свойства напрямую не наследуются, ни реализация не наследуется. Наследование интерфейсов представляет несомненный интерес и весьма полезно по другой причине, - оно позволяет реализовать в полной мере полиморфизм семейства классов VBA. К подробному рассмотрению этого вопроса мы сейчас и переходим.