Опубликован: 13.09.2006 | Уровень: для всех | Доступ: платный | ВУЗ: Тверской государственный университет
Лекция 5:

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

< Лекция 4 || Лекция 5: 123456 || Лекция 6 >
Аннотация: Типы и классы. Еще раз о понятии "класс". Что нового в классах "Office 2000". Создание класса "Личность". Объекты и переменные Объекты, класс которых определен пользователем. Объекты "родного" приложения. ActiveX-объекты Модуль класса. Свойства. Сокрытие свойств. Конструкторы и деструкторы. Стандартные события. Стандартные события Initialize и Terminate. Два конструктора класса Rational Процедуры - свойства. Как создаются процедуры - свойства. Синтаксис Let, Get и Set. Классы, как упаковка. Семейство классов и процедуры - свойства. Методы. События. Классы, объекты With Events и обработчики событий . Модуль класса с объектом WithEvents. Объект WithEvents. События собственных классов. Как создать класс с событиями. Как зажигаются события. Где и как следует создавать обработчики событий для экземпляров класса. Связывание объектов Реальные объекты и инициирование событий. Итоги.

Программный код большинства примеров данной лекции можно найти в проектах, доступных для просмотра: BookOne, BookTwo, DocOne, DocTwo.

Типы и классы

Еще раз о понятии "класс"

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

"Программирование в классах" является основным способом работы современного программирования.

За примерами далеко ходить не нужно. Так построена операционная система Windows, - окно являются ее основным объектом. Сам Office 2000 полностью построен на классах и работе с объектами этих классов, - здесь все, начиная от приложения и кончая отдельным символом, рассматривается как объект некоторого класса. Профессиональный прикладной программист, работающий в некоторой проблемной области и решающий разнообразные задачи из этой области, как правило, начинает с создания классов, описывающих специфику данной проблемной области. Затем уже решение тех или иных специальных задач он описывает в терминах работы с объектами данной проблемной области.

VBA позволяет программисту создавать собственные классы. Синтаксически класс представляет отдельный модуль специального вида - модуль класса. Мы постараемся сейчас детально и на примерах разобраться во всех особенностях этой важной конструкции.

Что нового в классах "Office 2000"

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

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

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

Создание класса "Личность"

В предыдущей лекции о типах данных мы ввели пользовательский тип Person. Там же мы показали, что прямой доступ к полям записи позволяет программисту свободно работать с данными этого типа. И все же Person в чем-то "ущербен"... А не хватает ему собственных операций: если бы наши переменные Петров и Козлов имели тип, например, Integer, можно было бы их сравнивать, складывать и умножать, присваивать значения и многое другое. Понятно, что умножение данных типа Person вряд ли разумно, но зато для него можно определить свои операции. Вот, например, какие операции можно определить для этого типа:

  • InitPerson - инициализация полей записи;
  • PrintPerson - печать полей записи;
  • CopyPerson(Source As Person) - копирование источника (записи Source ) - аналог оператора присвоения;
  • WhoIs - более специфическая операция, с определенной достоверностью определяющая пол, анализируя имя и фамилию.

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

Синтаксически классы в VBA оформляются в виде модуля класса . Поэтому начинать создание класса в Редакторе Visual Basic нужно с выбора в меню Insert пункта Class Module. Этот модуль имеет такую же структуру, как и стандартный модуль, о котором мы подробно уже рассказали. Модуль состоит из двух разделов - объявлений и методов. В первом из них естественным образом описываются свойства класса, а во втором - его методы. И здесь действуют спецификаторы области действия Public и Private. Public - свойства и Public -методы составляют интерфейс класса. Только к этим свойствам и методам можно обращаться при работе с объектами класса, объявленными в других модулях, где класс является видимым.

Мы расширили ранее созданный тип Person до класса, названного нами Личность, путем добавления операций над данными класса. Часть из этих операций уже упомянута, другие ясны из контекста. Нам кажется разумным привести с самого начала полное описание класса, а потом уже, когда полная картина ясна, переходить к деталям. Создав модуль класса " Личность, мы поместили туда следующий текст:

Option Explicit

'Класс Личность
'Свойства класса: имя, отчество, фамилию, дату рождения 
'закроем от прямого доступа,
'получить и изменить их можно только через методы класса
Private Имя As String
Private Отчество As String
Private Фамилия As String
Private ДатаРождения As Date

Public Sub InitPerson(ByVal FN As String, ByVal LN As String,  _
	ByVal DoB As Date)
    'Инициализация личности
    Имя = FN
    Фамилия = LN
    ДатаРождения = DoB
End Sub

Public Sub PrintPerson()
    'Печать в отладочном окне Immediate
    Dim S As String
    If WhoIs Then S = "родилась" Else S = "родился"
    Debug.Print Имя, Отчество, Фамилия, S, ДатаРождения
End Sub

Public Sub CopyPerson(You As Личность)
    Имя = You.ВашеИмя
    Фамилия = You.ВашаФамилия
    ДатаРождения = You.ВашаДатаРождения
End Sub

Public Function WhoIs() As Boolean
    'Пытается определить пол личности, анализируя имя и фамилию
    'Возвращает True, если думает, что имеет дело с женщиной.
    Dim F1 As Boolean, F2 As Boolean
    F1 = ПоследняяБуква(Имя) = "А" Or ПоследняяБуква(Имя) = "Я"
    F2 = ПоследняяБуква(Фамилия) = "А" Or ПоследняяБуква(Фамилия) = "Я"
    If F1 And F2 Then
        'можно полагать, что наша Личность - женщина
        WhoIs = True
    ElseIf Not F1 And Not F2 Then
        WhoIs = False
    Else 'Есть сомнения
        If Отчество = "" Then
            Отчество = InputBox(Имя & " " & Фамилия _
            & "! " & "Назовите отчество, пожалуйста.")
        End If
        WhoIs = ПоследняяБуква(Отчество) = "А"
    End If
End Function

Public Sub SayWhoIs()
'   Вывод сообщения о поле и возрасте личности
    If WhoIs Then
        MsgBox ("Думаю," & Имя &  _
			", Вы из прекрасной половины человечества!")
    ElseIf Year(ДатаРождения) > 1967 Then
        MsgBox ("Думаю, " & Имя & ", Вы - молодой человек!")
    Else
        MsgBox ("Думаю, " & Фамилия & ", - мужчина!")
    End If
End Sub

Private Function ПоследняяБуква(ByVal W As String) As String
    'Внутренняя функция: возвращает в верхнем регистре 
	'последнюю букву слова W
    ПоследняяБуква = UCase(Right(W, 1))
End Function

Public Property Get ВашеИмя() As String
    ВашеИмя = Имя
End Property

Public Property Let ВашеИмя(ByVal vNewValue As String)
    Имя = vNewValue
End Property
Public Property Get ВашеОтчество() As String
    ВашеОтчество = Отчество
End Property

Public Property Let ВашеОтчество(ByVal vNewValue As String)
   Отчество = vNewValue
End Property

Public Property Get ВашаФамилия() As String
    ВашаФамилия = Фамилия
End Property

Public Property Let ВашаФамилия(ByVal NewValue As String)
    Фамилия = NewValue
End Property

Public Property Get ВашаДатаРождения() As Date
    ВашаДатаРождения = ДатаРождения
End Property

Public Property Let ВашаДатаРождения(ByVal NewValue As Date)
    ДатаРождения = NewValue
End Property

Private Sub Class_Initialize()
    Имя = "Адам"
    Фамилия = "Человек"
    ДатаРождения = #1/1/100#
End Sub
4.1.

Прокомментируем этот довольно длинный текст.

  • Первое, что мы сделали, - перешли на русский язык при задании имен свойств и методов.
  • С точностью до имен все свойства класса Личность совпадают с полями типа Person. Кстати, мы сделали все свойства закрытыми ( Private ), и теперь вне класса нет прямого доступа к его полям (свойствам).
  • В класс Личность добавлено 5 общих методов: InitPerson, PrintPerson, CopyPerson, WhoIs, SayWhoIs и по паре методов Get и Let на каждое закрытое свойство. В классе есть и закрытая для внешнего использования функция " ПоследняяБуква ", и обработчик события Initialize.
  • Метод Init в том или ином виде должен быть определен в каждом классе. Это первый вызываемый метод объекта. Прежде чем начать работу с объектом, его нужно инициализировать. В нашем классе эту работу и делает метод InitPerson.
  • Метод Print также присутствует почти в каждом классе - нужно же распечатать информацию об объекте! - в PrintPerson вызывается метод WhoIs.
  • CopyPerson - еще один общий, часто необходимый метод, позволяющий реализовать настоящее присвоение, когда копируется не ссылка, а значения полей класса, что позволяет иметь не две ссылки на один объект, а два идентичных объекта.
  • Булева функция WhoIs - метод, специфический для нашей задачи. Это попытка определить пол по имени и фамилии. Применяется примитивный, но обеспечивающий высокую достоверность для русских имен и фамилий алгоритм. По ходу дела потребовалось ввести вспомогательную функцию " ПоследняяБуква ".
  • Метод SayWhoIs вызывает WhoIs, дополнительно определяет возраст (только для мужчин) и выводит соответствующее сообщение в окно Message.
  • Закрытая для внешнего использования функция ПоследняяБуква возвращает в верхнем регистре последнюю букву слова. Эта задача решается двумя вызовами функций работы со строками Right и UСase. Первая возвращает "хвост" слова, вторая - преобразует результат в верхний регистр.
  • Подробнее скажем о закрытых свойствах и специальных методах Get и Let. Вообще говоря, свойства можно не закрывать, а специальные методы не вводить. Но VBA позволяет следовать традициям объектно-ориентированного программирования, согласно которым считается правильным не давать возможности непосредственного изменения свойств, поскольку иногда это может привести к некорректному состоянию объекта. Поэтому доступ к свойствам закрывается, для чего достаточно объявить их с атрибутом Private, но зато вводятся специальные методы Get (для получения значения свойства) и Let (для изменения значения на новое). Заготовки для этой пары свойств строятся автоматически, если Вы при вставке метода указали (пометив флажок Property ), что он должен быть свойством.
  • С каждым из объектов созданного Вами класса связываются два события: Initialize и Terminate. Первое возникает при первоначальном обращении к объекту, второе - по окончании работы с ними. В нашем примере в методе Initialize даем объекту инициализацию, восходящую к "Адаму".

Завершим изложение примером работы с объектами класса, его методами и свойствами:

Public Sub Знакомство()
    Dim UserOne As New Личность
    Dim UserTwo As New Личность
    Dim UserThree As New Личность
    Debug.Print UserOne.ВашеИмя
    UserOne.InitPerson FN:="Петр", LN:="Петров", DoB:=#1/23/1968#
    UserTwo.InitPerson FN:="Анна", LN:="Козлова", DoB:=#7/21/1968#
    UserOne.PrintPerson
    UserTwo.PrintPerson
    UserOne.SayWhoIs
    UserTwo.SayWhoIs
    UserTwo.ВашаФамилия = UserOne.ВашаФамилия & "а"
    Debug.Print UserOne.ВашаФамилия
    Debug.Print UserTwo.ВашаФамилия
    UserThree.InitPerson FN:="Анна", LN:="Керн", DoB:=#5/17/1803#
    UserThree.PrintPerson
    UserThree.SayWhoIs
End Sub

Вот какие результаты отладочной печати будут выданы в окно Immediate (отладки):

Адам
Петр           Петров        родился       23.01.68 
Анна           Козлова       родилась      21.07.68 
Петров
Петрова
Анна Петровна  Керн          родилась      17.05.1803

А такие окна сообщений появятся на экране, при уточнении данных о личности Анны Керн:

Отчество Анны Керн

Рис. 4.1. Отчество Анны Керн
Кто Анна?

Рис. 4.2. Кто Анна?
< Лекция 4 || Лекция 5: 123456 || Лекция 6 >
полина есенкова
полина есенкова
Дмитрий Вологжин
Дмитрий Вологжин
Добрый день, прошел тесты с 1 по 9, 10 не сдал, стал читать лекцию и всё пройденные тесты с 1 по 9 сбросились, когда захотел пересдать 10 тест.
Людмила Слесарева
Людмила Слесарева
Россия
Александр Орлов
Александр Орлов
Россия