Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторки 1-6 по Delphi.pdf
Скачиваний:
49
Добавлен:
08.04.2015
Размер:
1.09 Mб
Скачать

Языки программирования

Обязательно обратите внимание на небольшое изменение в порядке объявления классов. Раньше (см. листинги 3.2 и 3.3) описание каждого из классов начиналось с отдельного ключевого слова type, в новой версии кода для обеспечения видимости опережающего объявления класса TAutomobile мы ограничились одним словом type.

Еще одна синтаксическая особенность опережающего объявления в том, что заявление о существовании класса заканчивается не ключевым словом end, как того требует синтаксис (листинг 1). Вместо этого точка с запятой ставится сразу после инструкции class.

Добившись того, что класс TEngine узнал о существовании класса TAutomobile, усовершенствуем конструктор автомобиля (листинг 3.9).

Листинг 3.9. Исправление конструктора класса TAutomobile

constructor TAutomobile.Create; begin

fEngine:=TEngine.Create;

//создаем двигатель

fEngine.fAutomobile:=self;

//двигатель получил ссылку на автомобиль

fEngine.SetEnabled(False);

//исходное состояние — двигатель выключен

end;

 

Теперь, в момент создания автомобиля, ссылка на экземпляр класса TAutomobile будет передана в соответствующее поле экземпляра класса TEngine. Благодаря ссылке двигатель получает возможность обращаться к полям и методам автомобиля.

Нам осталось сделать последний штрих — дополнить метод включения/отключения двигателя SetEnabled() командой на остановку автомобиля (листинг 3.10).

Листинг 3.10. Остановка автомобиля в момент выключения двигателя

procedure TEngine.SetEnabled(Value: Boolean); begin

fEnabled:=Value; if Value=false then

if Assigned(fAutomobile) then {если есть связанный объект}

fAutomobile.fSpeed:=0;

end;

Ограничение видимости членов класса

При описании класса программист имеет право определять степень доступности (видимости) его полей, свойств и методов. Это один из способов защиты наиболее критичных элементов класса от несанкционированного вмешательства сторонних разработчиков. Область видимости поля (метода) класса зависит от того, в какой из четырех возможных секций оно объявлено: private, protected, public и published (листинг 3.11).

Листинг 3.11. Секции видимости членов класса

type

TAutomobile = class private

... { секция частных объявлений } protected

... { секция защищенных объявлений } public

30

СКФУ Кафедра компьютерной безопасности

Языки программирования

... { секция общих объявлений } published

... { секция опубликованных объявлений } end;

Поля и методы, доступ к которым нежелателен, обычно размещаются в секциях private и protected. Наиболее защищена секция private. К размещенным в ней полям и методам возможно обращение только из того же программного модуля, в котором описан этот класс. Секция protected несколько приоткрывает завесу секретности — находящаяся в ней информация без каких-либо ограничений доступна для классов-потомков. Секция public предоставляет объявленные в ней поля и методы для общего пользования всем желающим. Секция published самая доброжелательная. Например, объявленными в ней данными умеет пользоваться Инспектор объектов. Это возможно благодаря тому, что для этой секции класса генерируется информация о времени выполнения (Run Time Type Information, RTTI). Поэтому в секции published обычно объявляют все свойства и обработчики событий объекта.

Свойства объекта

Как правило, объект не должен предоставлять прямой доступ к своим полям. Это требование инкапсуляции, благодаря которому поддерживается целостность объекта. Поэтому при проектировании класса одновременно с полями объявляют особых посредников, называемых

свойствами (properties).

В первую очередь в обязанность свойств входит проверка корректности передаваемых в поля данных, для этого они могут задействовать все мощь языка Delphi. В самом простейшем случае синтаксическая конструкция объявления свойства выглядит следующим образом:

property Имя_свойства: Тип_свойства Read (способ чтения) Write (способ записи);

За инструкциями Read и Write могут следовать названия процедур, соответственно отвечающих за чтение данных из поля и запись данных в поле.

Возьмем в качестве примера класс двигателя TEngine, он обладает парой полей fEnabled и fAutomobile, которые следует обязательно защитить. Листинг 3.12 демонстрирует один из возможных сценариев усовершенствования класса.

Листинг 3.12. Объявление свойств

type TEngine=class private

fEnabled :boolean; //двигатель включен - true, выключен - false

fAutomobile:TAutomobile; //ссылка на автомобиль public

procedure SetEnabled(Value:Boolean); //запуск или останов двигателя

function GetEngineState:boolean; //состояние двигателя published

property Enabled:boolean Read fEnabled Write SetEnabled;

property Automobile:TAutomobile Read fAutomobile; end;

Все поля класса "спрятаны" в секцию private, что существенно усложнит обращение к полям извне. Наоборот, методы и свойства, к которым мы намерены разрешить полный доступ, размещены в секции публичных объявлений. Теперь для включения/отключения двигателя надо воспользоваться свойством Enabled. Еще большую степень защиты мы обеспечили полю

31

СКФУ Кафедра компьютерной безопасности

Языки программирования

fAutomobile, хранящему ссылку на автомобиль, в который установлен двигатель — свойство допускает только чтение информации из поля.

Особенности объявления методов

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

статические (директива static);

динамические (директива virtual);

виртуальные (директива dynamic).

По умолчанию, любой вновь описанный метод, становится статическим. Такое название метод заслужил из-за того, что во время компиляции статическому методу выдается постоянный адрес, такой способ называется статическим связыванием (static binding). У метода с постоянным адресом есть две особенности: высокая скорость вызова (что не может не радовать) и абсолютная невозможность изменить поведение этого метода в дочерних классах (что является отрицательной стороной статического связывания). Одним словом, объявляя статический метод, мы должны понимать, что наносим удар по полиморфизму (наследник класса утратит возможность переопределить этот метод).

В отличие от своего статического собрата виртуальные и динамические методы исповедуют идеи позднего связывания (late binding). Это означает, что адреса таких методов не "высечены в граните", а могут изменяться. Так адреса виртуальных методов класса заносятся в таблицу виртуальных методов этого класса, а адреса динамических методов — в специальный список методов этого класса. Благодаря технологии позднего связывания доступ к виртуальным и динамическим методам осуществляется несколько медленнее, но зато они допускают переопределение своего поведения у классов-потомков.

Поля класса и методы класса

Одно из правил объектно-ориентированного программирования предполагает, что обращение к полям и методам, описанным в классе, невозможно до тех пор, пока из класса не будет создан объект — экземпляр класса. С точки зрения программы Delphi это означает, что начало работы со свойствами и методами объекта должно предваряться вызовом его конструктора Create().

Однако из правил существуют исключения. В состав класса могут входить особые поля и методы, которые остаются доступными даже в отсутствие экземпляра объекта. Такие поля и методы называют соответственно полями класса (class fields) и методами класса (class methods).

По своей сути поле класса представляет собой обычную переменную, для ее объявления следует воспользоваться ключевыми словами class var или просто var.

Метод класса представляет собой процедуру или функцию с первым словом в заголовке class,

например class procedure или class function.

Благодаря полю класса и методу класса мы можем внести очередное усовершенствование класса двигателя TEngine (листинг 3.13).

Листинг 3.13. Объявление поля класса и метода класса TEngine

TEngine=class private

32

СКФУ Кафедра компьютерной безопасности

Языки программирования fEnabled :boolean;

fAutomobile:TAutomobile; public

class var fMax_HorsePower : word; //переменная класса class function GetMax_HorsePower : word; //метод класса

...

end;

{реализация функции класса}

class function TEngine.GetMax_HorsePower: word; begin

Result:=fMax_HorsePower; end;

Как и утверждалось ранее, для обращения к полям и методам класса совсем не обязательно создавать объект, вполне допустимо воспользоваться строками кода из листинга 3.14.

Листинг 3.14. Обращение к полю класса и методу класса TEngine

var X:Word; begin

with TEngine do begin

fMax_HorsePower:=250;

X:=GetMax_HorsePower; end;

end;

Иерархия наследования

Вновь возвратимся к очень важному ингредиенту ООП — наследованию. Мы уже знаем, что в основе концепции наследования лежит возможность строительства нового класса на базе уже существующего родительского класса. Благодаря наследованию дочерний класс впитывает в себя все родовые черты своего предка. Ограничений на длину цепочки наследования нет, в визуальной библиотеке компонентов Delphi объявлены классы, имеющие в родословной больше десятка предков. Таким образом, самый последний в древе наследования класс вбирает в себя все лучшее от всех своих предшественников.

Для того чтобы понять какие уникальные возможности предоставляет программисту наследование, перейдем к практической стороне вопроса. В нашем распоряжении уже имеется класс TAutomobile, олицетворяющий все наши знания в области ООП. Попробуем развить первоначальный успех и создать программный класс, способный смоделировать пассажирский автобус — класс TAutobus.

Автобус — это всего лишь разновидность автомобиля. У него, как и у автомобиля, есть двигатель, автобус также может набирать и снижать скорость движения. Одним словом, за основу нашего нового класса можно взять уже существующий TAutomobile и дополнить его всего одной возможностью — перевозить пассажиров (листинг 3.15).

Листинг 3.15. Создание дочернего класса TAutobus

type TAutobus=class(TAutomobile) private

fPassenger:byte; //поле — число пассажиров

procedure SetPassenger(Value:byte); //управление числом пассажиров

33

СКФУ Кафедра компьютерной безопасности