
- •Тема 5.3. Средства объектно-ориентированного программирования в vb
- •5.3.1. Две роли классов в ооп и типы данных в vb
- •5.3.2. Средства создания классов в vb
- •5.3.2.1. Средства создания пользовательских классов
- •5.3.2.2. Пошаговое руководство для создания приложения с классами
- •Определение класса
- •Создание кнопки для тестирования класса
- •Запуск приложения
- •5.3.3. Взаимодействие, взаимное различие и сходство форм, модулей и классов
- •5.3.4. Создание объектной модели и приложений с использованием классов
- •5.3.5. Иерархия классов и наследование
- •Наследование и тождественность
- •Базовые классы и повторное использование кода
- •Взаимозаменяемые производные классы
- •Неполные иерархии классов
- •Глобальные изменения производных классов через базовый класс
- •Изменение структуры базовых классов после развертывания
- •Проблема уязвимости базовых классов
- •Сведение к минимуму проблем уязвимости базовых классов
- •5.3.6. Задачи для самостоятельного решения по теме «Средства объектно-ориентированного программирования в Visual Basic»
- •Практикум
- •5.3.7. Тестовые задания по теме «Средства объектно-ориентированного программирования в vb»
- •Тема 5.3. Средства объектно-ориентированного программирования в Visual Basic Страница 85
Запуск приложения
Запустите приложение, нажав клавишу F5.Нажмите кнопку в форме, чтобы вызвать процедуру тестирования. Отображается сообщение, в котором указано, что UserName имеет исходное значение "MOORE, BOBBY", поскольку процедурой вызван метод Capitalize() объекта.
Нажмите кнопку ОК, чтобы закрыть окно сообщения. В процедуре Button1 Click( ) изменяется значение свойства UserName и отображается сообщение о том, что свойство UserName получает новое значение "Worden, Joe".
5.3.3. Взаимодействие, взаимное различие и сходство форм, модулей и классов
Рассмотрим сначала взаимодействие, взаимное различие и сходство форм, модулей и классов на примере.
Пример 5.3-2. Создать проект из двух форм, двух модулей и класса.
Рассмотрим программный код, представленный на рис. 5.3-2, а также результат его работы на рис. 5.3-3.
-
Module Module1
Public Форма2 As New Form2
Public Объект As New Класс
End Module
Module Module2
Public M2 As String = "M2"
Public Sub Процедура_модуля2()
Форма2.F2 = "Модуль 2 изменил переменную F2 из формы 2"
End Sub
End Module
Public Class Класс
Public C1 As String = "C1"
Public Sub Процедура_класса( )
M2 = "Объект изменил переменную M2 из модуля M2"
End Sub
End Class
Public Class Form2
Public F2 As String = "F2"
Public Sub Процедура_формы2()
Объект.C1 = _
"Форма2 изменила переменную С1 из Объекта" & vbNewLine
TextBox1.Text = Объект.C1
End Sub
End Class
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button1.Click
Dim SS As String = ""
SS = SS & M2 & vbNewLine
SS = SS & Объект.C1 & vbNewLine
SS = SS & Форма2.F2 & vbNewLine
Процедура_модуля2( )
SS = SS & Форма2.F2 & vbNewLine
Объект.Процедура_класса()
SS = SS & M2 & vbNewLine
TextBox1.Text = SS
Форма2.Процедура_формы2()
Форма2.Show()
End Sub
End Class
Рис. 5.3-2
Рис. 5.3-3
Рассмотрим сходство и различия трех модулей, а именно стандартного Module2, модуля формы Form2 и модуля класса Класс. Очевидно, что их код почти одинаков. Код всех этих трех модулей содержит объявление переменной и объявление процедуры. И переменная, и процедура объявлены как Public, чтобы и той, и другой можно было пользоваться из любого модуля проекта.
Когда форма, модуль и класс могут начать работу?
Если форма - стартовый объект, VB сам, без всякого вмешательства загружает ее и отображает на экране.
Стандартные модули тоже безо всяких забот программиста готовы к работе и использованию сразу после запуска проекта.
Это значит, что форма Form1 и оба модуля готовы к работе и использованию сразу после запуска проекта.
Что же касается класса и не стартовой формы, здесь дело другое. В нашем проекте забота о том, чтобы они пришли в рабочее состояние, лежит на первом стандартном модуле. Если необходимо использовать класс как объект, то, чтобы класс заработал, нам нужно из него создать объект. Что и делает оператор
-
Public Объект As New Класс
Форма тоже класс. А раз так, то, чтобы она заработала в проекте, из нее тоже должен быть создан объект и показан на экране.
Если форма - стартовый объект, эти заботы берет на себя VB.
Если форма - не стартовый объект, программист должен сам создать ее как объект из ее класса, а затем показать на экране. Это можно реализовать с помощью двух операторов.
Оператора, который создает форму, как объект класса Form2:
-
Public Форма2 As New Form2
и оператора, показывающего форму Форма2.Show().
Строки стандартного модуля, объявляющие переменные, выполняются автоматически.
Поэтому объекты Объект и Форма2, объявленные в модуле Module1, будут созданы сразу же в начале работы проекта, так как стандартный модуль, в отличие от класса и формы (если она не стартовая, конечно) готов к работе сразу после запуска проекта.
Когда программист в режиме проектирования работает над формой Form2, добавляет в нее элементы управления, пишет код, он создает и видит перед собой класс (не объект) Form2. Когда же запускается проект и выполняется оператор Public Форма2 As New Form2, то порождается из этого класса объект Форма2, как экземпляр класса Form2. Форма (объект, а не класс) порождена, и можно пользоваться ее переменными и процедурами. Но на экране она не видна. Чтобы ее увидеть и пользоваться ее элементами управления, необходимо выполнить оператор Формa2.Show(). Аналогично, когда в режиме проектирования пишется код модуля класса, то создается класс, а когда запускается проект и выполняется оператор Public Объект As New Класс, то порождается из этого класса объект Объект как экземпляр класса Класс.
В чем же отличие формы от класса? В том, что создатели VB для удобства разработчиков снабдили формы механизмом визуализации. Это значит, что как в режиме проектирования, так и в режиме работы форма на экране видима. Специальные, скрытые от программиста методы рисуют и перерисовывают как форму, так и все ее элементы управления.
Класс же лишен механизма визуализации. Поэтому объекты, порожденные из него, невидимы. У них не может быть ни кнопок, ни меток, ни других элементов управления.
Еще раз рассмотрим правила обращения к переменным и процедурам. Ниже под модулем будем понимать или форму, или класс, или стандартный модуль.
Если переменная или процедура объявлены с помощью слова Public, то они видны и доступны не только из своего модуля, но и из других модулей проекта.
Грамматически обращение к переменным и процедурам разных модулей происходит следующим образом:
для обращения к переменной или процедуре, объявленной в стандартном модуле, достаточно написать имя переменной или процедуры без указания имени модуля;
для обращения к переменной или процедуре, объявленной в классе, нужно перед их именем написать имя объекта этого класса с точкой;
для обращения к переменной или процедуре, объявленной в форме, нужно перед их именем писать имя экземпляра класса этой формы с точкой.
Перед именем переменной или процедуры, объявленной в стандартном модуле, имя модуля писать не запрещено. Это бывает даже необходимо, когда в нескольких стандартных модулях объявлены переменные или процедуры с одинаковыми именами. Иначе их не различишь.
Все вышесказанное касается случая, когда необходимо обратиться к переменной или процедуре, объявленной в чужом модуле. Когда же нужно обратиться к переменной или процедуре, объявленной в своем модуле, все просто: пишется имя переменной или процедуры. Иногда, правда, бывает удобно или даже необходимо указать имя хозяина или Me. Это не возбраняется (правда, в случае стандартного модуля слово Me писать нельзя).
Пример 5.3-3. Способы обращения к собственной переменной.
Рассмотрим разные способы обращения к собственной переменной, дающие один и тот же результат (рис. 5.3-4).
-
‘Вторая форма
Public F2 As String = "F2"
Public Sub Процедура_формы2()
TextBox1.Text = F2 : TextBox1.Text = Me.F2 : TextBox1.Text = Форма2.F2
End Sub
‘Второй модуль
Dim SM1, SM2 As String
Public M2 As String = "M2"
Public Sub Процедура_модуля2()
SM1 = M2 : SM2 = Module2.M2
End Sub
'Класс
Dim SC1, SC2, SC3 As String
Public C1 As String = "C1"
Public Sub Процедура_класса()
SC1 = C1 : SC2 = Me.C1 : SC3 = Oбъект.C1
End Sub
Рис. 5.3-4
Из текста процедуры Button1_Click( ) примера (рис. 5.3.3-1) становится также ясно, что с переменными и процедурами формы можно работать еще до того, как форма появилась на экране.
Пример 5.3-4. Создать несколько объектов из одного класса.
Для создания нескольких объектов из одного класса необходимо создать проект из формы, модуля и класса. На форму поместить кнопку, текстовое поле и ввести программный код, приведенный на рис. 5.3-5. Результат представлен на рис. 5.3-6.
-
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim SS As String = ""
SS = SS & CStr(Объект1.С) & vbNewLine
SS = SS & CStr(Объект2.С) & vbNewLine
Объект1.С = 1 : Объект2.С = 2
SS = SS & CStr(Объект1.С) & vbNewLine
SS = SS & CStr(Объект2.С) & vbNewLine
Объект1.Процедура()
SS = SS & CStr(Объект1.С) & vbNewLine
SS = SS & CStr(Объект2.С) & vbNewLine
TextBox1.Text = SS
End Sub
End Class
Module Module1
Public Объект1 As New Класс
Public Объект2 As New Класс
End Module
Public Class Класс
Public С As Integer = 10
Public Sub Процедура()
Объект1.С = 101
Объект2.С = 102
End Sub
End Class
Рис. 5.3-5
Рис.
5.3-6
Видно, что модуль создает из класса Класс два объекта: Объект1 и Объект2. При создании они абсолютно одинаковы и размещаются рядышком в оперативной памяти. В каждом объекте располагается ячейка под переменную С.
В программном коде класса переменная С инициализируется значением 10, а это значит, что она станет такой в обоих объектах, что и подтверждают результаты выполнения первых двух строк процедуры Button1_Click( ).
После выполнения следующих двух строк процедуры объекты перестают быть близнецами. Теперь в ячейке С у первого объекта единица, а у второго – двойка.
Объект может и сам изменять значения переменных, как в себе, так и в своем «братце». Это видно из кода процедуры в классе. Таким образом, родившись одинаковыми, близнецы в процессе жизни могут изменяться.
Пример 5.3-5. Создать несколько объектов-форм из одного класса формы. Создадим проект из двух форм и модуля. На форму 1 поместите кнопку, на форму 2-3 кнопки. Покажем, что из одного класса формы можно порождать несколько объектов-форм, причем эти объекты ведут себя так же, как и объекты, порождаемые из модуля класса в предыдущем примере. Поскольку работа объектов-форм с переменными и процедурами неотличима от таковой работы прочих объектов, то ее рассматривать не будем, а займемся более наглядной работой с цветом фона.
Введем программный код, приведенный на рис. 5.3-7.
-
'Модуль
Module Module1
Public Форма1 As New Form2
Public Форма2 As New Form2
End Module
‘код Form1
Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button1.Click
Форма1.Show()
Фopмa2.Show()
End Sub
End Class
‘Форма 2
Public Class Form2
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button1.Click
Me.BackColor = Color.Blue
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs)
Handles Button2.Click
Me.BackColor = Color.Red
End Sub
Private Sub Button3_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button3.Click
Фopмa1.Text = "Форма1"
Форма1.BackColor = Color.Black
Форма2.Техt = "Форма2"
Форма2.ВасkСоlоr = Color.White
End Sub
End Class
Рис. 5.3-7
Запустить проект и нажать кнопку формы 1, на экране будут отображены две совершенно одинаковые формы-близнеца с тремя кнопками каждая. Даже заголовок у них одинаковый - Form2. При щелчках по первым двум кнопкам близнецов каждый близнец красит себя, то в синий, то в красный цвет. Только себя. Потому что в коде используется Me. Таким образом, близнецы очень скоро перестают быть похожими. Третья кнопка показывает, что каждая из форм может изменять не только себя, но и сестру.
Ранее уже были рассмотрены проблемы видимости, когда переменные, объявленные внутри процедуры, являлись локальными в процедуре, т. е. невидимыми снаружи процедуры. Поэтому их нельзя было использовать в других процедурах модуля.
Когда проект состоит из единственного модуля формы, рассмотренных ранее областей видимости было достаточно. Теперь, когда наши проекты состоят из нескольких модулей, встает вопрос о видимости переменных, процедур и других элементов VB из других модулей. Также уже известно, что для того, чтобы элемент был виден из других модулей, достаточно объявить его не словом Dim, а словом Public.
Обычно различают области видимости пяти уровней (в порядке увеличения охвата):
блок внутри процедуры или функции;
процедура или функция;
модуль;
проект;
неограниченная область.
Для систематизации знаний об областях видимости переменных, констант и процедур рассмотрим пример.
Пример 5.3-6. Анализ области видимости.
Введем следующий программный код, приведенный на рис. 5.3-8.
-
Public Class Class1
Dim C As Integer
Public A As Integer
Private В As Integer
Const M As Integer = 3
Public Const К As Integer = 1
Private Const L As Integer = 2
Private Sub Проц()
Dim C1 As Integer
End Sub
Sub Проц1( )
Const L1 As Integer = 4
End Sub
Public Function Функц() As String
Dim D As Integer
Return "Привет"
End Function
End Class
Рис. 5.3-8.
Проанализируем работу примера и рассмотрим его области видимости, начиная с самой узкой и кончая самой широкой, с учетом того, что областью видимости можно управлять при помощи модификаторов доступа (Public, Private, Protected, Friend, Protected Friend):
Локальные переменные и константы.
Внутри процедур и функций переменные могут быть объявлены только при помощи слова Dim, а константы - только при помощи Const. Это знакомые блочная и локальная области видимости и знакомые локальные переменные и константы. Они видны только в той процедуре, функции или блоке, в которых объявлены.
Теперь поговорим об элементах, объявленных вне процедур и функций. Это переменные, константы, процедуры и модули. Их пространство - три нижние области видимости. Они могут быть видны или только в том модуле, где они объявлены, или во всем проекте, или в неограниченной области в зависимости от того, при помощи каких слов объявление было сделано.
Область видимости - модуль.
Слова Dim или Private для переменной и слова Const или Private Const для константы делают их видимыми только в своем модуле. Их область видимости - весь этот модуль, включая все процедуры, функции. Это модульные переменные и константы.
Таким образом, для объявления модульных переменных и констант можно обойтись и без модификатора Private (достаточно оператора Dim). Любой другой элемент (процедура, модуль), чтобы быть видимым аналогичным образом только в своем модуле, объявляется модификатором Private.
Область видимости - проект.
Если необходимо, чтобы элемент VB был виден во всем проекте, но не дальше, объявляем его модификатором Friend. Часто программисты употребляют вместо Friend более привычный модификатор Public, обеспечивающий неограниченную видимость.
Неограниченная область видимости.
Модификатор Public делает элемент неограниченно видимым. Такие элементы называют глобальными для всего решения.
Видимость по умолчанию.
Если совсем убрать модификатор доступа к классам и модулям:
-
Class Класс1
‘по умолчанию будут иметь доступ Friend
End Class
Если совсем убрать модификатор доступа к процедуре:
-
Sub Pr()
‘по умолчанию будут иметь доступ Public.
End Sub
Переменные и другие программные элементы разных модулей или разных процедур могут иметь одинаковые имена. Как в этом случае VB определяет, какой из видимых одноименных элементов имеется в виду в каждом конкретном случае? Здесь вступает в действие эффект затенения: из нескольких одноименных элементов всегда имеется в виду более локальный, т. е. тот, чья зона видимости меньше. Это значит, что локальные элементы имеют предпочтение перед модульными элементами, а модульные элементы – перед глобальными.
Классы и модули. Основное различие между классами и модулями состоит в том, что классы могут быть инициализированы как объекты, а модули – нет. Существует только одна копия данных стандартного модуля, поэтому при изменении одной частью программы общей переменной в стандартном модуле при последующем чтении этой переменной любая другая часть программы получает измененное значение. Напротив, объект данных существует отдельно для каждого экземпляра объекта. В отличие от стандартных модулей, классы могут реализовывать интерфейсы.
Когда модификатор Shared применяется к члену класса, он связан с самим классом непосредственно, а не через экземпляр класса. Непосредственный доступ к члену осуществляется с помощью имени класса. Тем же способом осуществляется доступ к членам модуля.
Классы и модули используют различные области действия для своих членов. Члены, определенные внутри класса, находятся в определенном экземпляре класса и существуют только во время существования объекта. Для доступа к членам класса за пределами класса необходимо использовать полные имена в формате Объект.Член.
С другой стороны, члены, объявленные в модуле, общедоступны по умолчанию, и доступ к нему может осуществить любой код, имеющий доступ к модулю. Это означает, что переменные в стандартном модуле являются фактически глобальными переменными, так как они видимы из любой части проекта и существуют во время выполнения программы.
Общие члены. Можно управлять тем, является ли член класса общим или членом экземпляра.
Объектная ориентация. Классы являются объектно-ориентированными, а модули — нет. Пользователь может создать один или несколько экземпляров класса.
Различия между свойствами и переменными в VB. Переменные и свойства редоставляют значения, к которым можно получить доступ. Однако существуют различия в хранении и реализации.
Переменные - variable соответствует определенному месту в памяти. Можно определить переменную при помощи одиночного оператора объявления. Переменная может быть local variable, которая определена внутри процедуры и доступна только в пределах этой процедуры, или она может быть member variable, которая определена в модуле, классе или структуре, но не внутри процедуры. Переменная члена также называется field.
Свойства - property является элементом данных, определяемым для модуля, класса или структуры. Свойство определяется в блоке кода между инструкциями Property и End Property.Блок кода содержит одну из процедур Get или Set или их вместе.Эти процедуры называются property procedures или property accessors.Помимо извлечения или сохранения значений свойств, над ними также можно выполнять пользовательские действия, такие как обновление счетчика доступа.
Отличия - В следующей таблице показаны некоторые важные различия между переменными и свойствами.
-
Рассматриваемый параметр
Переменная
Свойство
Объявление
Одиночный оператор объявления
Последовательность инструкций в блоке кода
Реализация
Одно место хранения
Исполняемый код (процедуры свойства)
Хранение
Непосредственно связана со значением переменной
Обычно имеет внутреннее хранилище, недоступное за пределами свойства, которое содержится внутри класса или модуля
Значение свойства может существовать или не существовать в виде хранимого элемента 1
Исполняемый код
Нет
Должно иметь по крайней мере одну процедуру
Чтение и доступ на запись
Чтение/запись или только чтение
Чтение/запись, только чтение или только запись
Дополнительные действия (в дополнение к принятию или возвращению значения)
Невозможно
Может выполняться как часть задания или получения значения свойства
В отличие от переменной, значение свойства может не соответствовать непосредственно одному элементу хранилища. Хранилище может быть разбито на части для удобства или безопасности, или значение может храниться в зашифрованном виде. В этих случаях процедура Get будет собирать фрагменты или расшифровать хранимое значение и процедура Set будет шифровать новое значение или разбивать его на составные части хранилища. Значение свойства может быть временным, например, время дня, в этом случае процедура Get будет вычислять его на лету при каждом обращении к свойству.
Подведем итог и сформулируем два правила:
Чем локальнее, тем лучше.
Встает вопрос: какую область видимости необходимо выбирать для каждой конкретной переменной? Объявлять ли ее глобальной, модульной или локальной? Здесь совет один - любую переменную объявляйте как можно более локальной, пусть ее область видимости будет как можно меньше. Если ее значение нужно только в одной процедуре и больше нигде, делайте ее локальной. Если ее значение нужно в нескольких процедурах одного модуля, а в других модулях нет, то делайте ее модульной. И только если значение переменной нужно в нескольких модулях, делайте ее глобальной. Такой подход обеспечит вашему проекту максимальную надежность и удобство в отладке.
Используйте процедуры с параметрами.
Второе правило: вместо процедур без параметров используйте процедуры с параметрами.
В общем, совет такой: с глобальными и модульными переменными работайте по возможности через параметры.