
- •Основные механизмы и положения объектно-ориентированного программирования
- •5.1. Инкапсуляция
- •Interface
- •Implementation
- •Interface
- •Implementation
- •Interface
- •Implementation
- •Interface
- •Implementation
- •Interface
- •Implementation
- •Interface
- •Implementation
- •5.2. Наследование
- •Interface
- •Implementation
- •Interface
- •Implementation
- •5.3. Жизненный цикл экземпляра класса
- •Interface
- •Implementation
- •Inherited;
- •Interface
- •Implementation
- •Interface
- •Implementation
- •Interface
- •5.4. Полиморфизм
- •5.4.1. Совместимость объектов
- •Класс в Экземпляр
- •Interface Type
- •Implementation
- •Interface
- •Implementation
- •If Figure is tLine
- •Interface
- •Implementation
- •Interface
- •Implementation
- •IColor: Integer;
Interface
Type
MthdClass = class
class Function Get5: Double;
End;
Implementation
class Function Mthd.Class.Get5: Integer;
{Описание метода Get5 класса MthdClass}
Begin
Result := 5;
end;
end.
Для вызова метода класса необходимо указать название класса и название метода со списком необходимых параметров. Название класса и его метода разделяются точкой:
<Класс>.<Метод>(<Список параметров>) ;
Использование метода класса отражено в следующем листинге 5.3.
Листинг 5.3. Использование метода класса
unit UsingClassMethods;
Uses DeclaringClassMethods;
{Подключаем модуль DeclaringClassMethods,
в котором описан класс MthdClass}
Interface
Implementation
Procedure UsingClass; {Описание процедуры UsingClass}
Var
A: Integer; {Описание целочисленной переменной А}
Begin
A := MthdClass.Get5; {Вызов метода класса по имени класса
и метода, в переменную А заносится
значение 5}
end;
end.
Отметим, что методы класса иногда называют статическими методами.
Перегружаемые методы
Перегружаемые методы аналогичны перегружаемым процедурам и имеют такой же механизм работы. Пример, возможного описания класса с перегружаемыми методами приведен в листинге 5.4.
Листинг 5.4. Описание класса с перегружаемыми методами
Туре
AClass = class
Function Mult(A, B: Integer): Integer; overload;
{Заголовок метода Mult с двумя целочисленными параметрами, возвращающий целочисленное значение}
Function Mult(A, В: Double): Double; overload;
{Заголовок метода Mult с двумя вещественными параметрами, возвращающий вещественное значение}
end;
Function AClass.Mult(A, B: Integer): Integer;
begin
Result := A * B;
end; {Описание первого варианта метода Mult}
Function AClass.Mult(A, B: Double): Double;
begin
Result : = A * B;
end; {Описание второго варианта метода Mult}
Области видимости элементов класса
Для разграничения доступа к свойствам и методам экземпляров классов между различными частями программы предусмотрены модификаторы доступа («видимости»), приведенные в табл. 5.1.
Модификатор доступа в Delphi (как и в Pascal, но в отличие от некоторых других языков программирования) относится не к конкретному свойству или методу класса, а ко всем элементам класса (свойствам и методам), описание которых располагается после указания модификатора. Один и тот же модификатор может указываться в описании класса более одного раза.
Сравнительная таблица модификаторов доступа в Pascal и Delphi Таблица 5.1
Модификатор |
Область видимости свойства или метода, помеченного модификатором |
|
|
Pascal |
Delphi |
Private |
описание класса и модуль, в котором описан класс, в том числе и для других классов |
также |
Protected |
не используется |
как у private + в классах, унаследованных от этого класса |
Public |
любая часть программы |
так же |
Published |
не используется |
как у public + в Инспекторе объектов Delphi для визуального построения программ |
Стандартное описание класса содержит свойства и методы, расположенные в порядке возрастания их видимости, но это правило не является обязательным.
Туре
……………………..
<Имя класса> = class
private
<Имя свойства 1>: <Тип свойства 1>;
{Описание свойств класса, имеющих область видимости private}
………………..
<Имя свойства N>: <Тип свойства N>;
<Заголовок метода 1>;
{Описание методов класса, имеющих область видимости private}
<3аголовок метода М>;
protected
<Имя свойства 1>: <Тип свойства 1>;
{Описание свойств класса, имеющих область видимости protected}
………………..
<Имя свойства N>: <Тип свойства N>;
<Заголовок метода 1>;
{Описание методов класса, имеющих область видимости protected}
………………..
<Заголовок метода М>;
public
<Имя свойства 1>: <Тип свойства 1>;
{Описание свойств класса, имеющих-область видимости public}
………………..
<Имя свойства N>: <Тип свойства N>;
<Заголовок метода 1>;
{Описание методов класса, имеющих область видимости public}
………………..
<Заголовок метода М>;
published
.........
{Описание специальных свойств
класса (property), имеющих область видимости published}
End;
Различные области видимости свойств и методов объекта предназначены для упрощения поддержания целостности информации в объектах. Рассмотрим класс, в котором содержатся три свойства — а, b и с, причем с является произведением а и b. Если свойства а, b и с будут иметь широкую область видимости public, то есть будут доступны из любого фрагмента программы, то объект — экземпляр такого класса может содержать некорректные данные, так как существует возможность изменения свойств а и b без пересчета свойства с. Для выхода из такой ситуации можно предложить два подхода, и оба они связаны с использованием областей видимости свойств объекта.
Первый подход (см. листинг 5.5) состоит в том, чтобы скрыть свойства а и b от вызывающих подпрограмм, назначив им узкие области видимости, например private или protected. Выбор того или иного модификатора определяется необходимостью использования скрываемых свойств в классах-потомках данного класса. Если такой необходимости нет, то назначается область видимости private, если объекты-потомки должны иметь прямой доступ к свойствам, то назначается область видимости protected.
В любом случае, внешние подпрограммы не смогут обратиться к свойствам а и b, поэтому придется предусмотреть методы, которые их устанавливают. В этих методах, помимо установки значений свойств, должен производиться пересчет свойства с. Это будет гарантировать целостность данных объекта при изменении свойств а и b.
Заметим, что методы установки должны иметь широкую область видимости, чтобы к ним можно было обратиться из любого места программы.
Листинг 5.5. Задание областей видимости. Первый подход
Unit UsingPrivatel; {Заголовок модуля}
Interface {Начало интерфейсной части}
Туре
ABC = class {Заголовок класса ABC}
private {Начало области видимости private)
a, b: Double; (Свойства а и b имеют узкую область
видимости}
public {Начало области видимости public}
с: Double; {Свойство с имеет широкую область
видимости}
Procedure SetA(NewA: Double);
{Метод SetK имеет широкую область видимости}
Procedure SetB(NewB: Double);
{Метод SetB имеет широкую область видимости}
end;
Implementation {Начало описательной части}
Procedure ABC.SetA(NewA: Double);
{Описание метода SetA класса А В С}
Begin
а : = NewA; {Установка значения свойства а.]
с := а * Ь; {Обновление значения свойства c-
поддержание целостности данных}
end;
Procedure ABC.SetB(NewB: Double);
{Описание метода SetB класса ABC
Begin
b := NewB; {Установка значения свойства b}
с := a * b; {Обновление значения свойства с -
поддержание целостности данных}
end;
end. {Окончание модуля}
При такой конструкции класса вызывающая подпрограмма не сможет изменить значения свойств а и Ь, не повлияв тем самым на значение свойства с, поэтому целостность данных не будет нарушена. Однако свойство с доступно для изменения, даже если его значение пересчитано при установке значений а и Ь. В итоге оно может измениться, вызвав несоответствие данных. Таким образом, лучше было бы скрыть свойство с, реализовав специальный метод доступа к его значению (листинг 5.6).
Листинг 5.6. Задание областей видимости. Второй подход
Unit UsingPrivate2; {Заголовок модуля}
Interface {Начало интерфейсной части}
Type
ABC2 = class {Заголовок класса ABC}
Private {Начало области видимости private}
с: Double; {Свойство с имеет узкую область видимости}
Public {Начало области видимости public}
a, b: Double; {Свойства а и b имеют широкую область видимости}
Function GetC: Double; {Метод GetC имеет широкую область видимости}
end ;
Implementation {Начало описательной части}
Function ABC2.GetC:Double;
{Описание метода GetC класса АВС2}
Begin
с := а*b; {Обновляем значение свойства с}
Result := с{ Возвращаем значение с вызывающей подпрограмме}
end;
end. {Окончание модуля}
При такой конструкции класса целостность данных не может быть нарушена вызывающими подпрограммами, если только они не находятся в одном модуле с описываемым классом, то есть, в данном случае, в модуле UsingPrivate2. Единственным недостатком такого подхода является постоянный пересчет значения с при каждом обращении к методу GetC. Поэтому наиболее оптимальным вариантом решения нашей задачи будет сокрытие всех свойств класса и реализация методов доступа к ним через методы (см. листинг 5.7).
Листинг 5.7. Задание областей видимости. Третий подход (оптимальный)
unit UsingPrivate3; {Заголовок модуля}