ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 10.01.2024
Просмотров: 1081
Скачиваний: 1
СОДЕРЖАНИЕ
ЛР 1. Операторы и выражения Delphi
Управление жизненным циклом объекта
Ограничение видимости членов класса
Особенности объявления методов
Принадлежность к родительскому контейнеру
Размещение и размеры элемента управления
Видимость и активность элемента управления
ЛР5. Обработка клавиатурных событий и событий мышки
, то создание и уничтожение объекта будет осуществлено за счет конструктора и деструктора родительского класса. В нашем примере мы не стали создавать индивидуальные методы Create() и Destroy() для двигателя TEngine. Это означает, что управление существованием двигателя будет осуществляться за счет унаследованных им методов класса-предка (в нашем случае TObject).
Практический аспект применения конструктора и деструктора рассмотрен в листинге 3.7.
Листинг 3.7. Создание и уничтожение объекта в коде программы
var A : TAutomobile; //объектная переменная
begin
A:=TAutomobile.Create; //создаем объект
... //операции с объектом
A.Destroy; //разрушаем объект
end;
Опережающее объявление класса
Разрабатывая даже столь простую имитацию транспортного средства, нам все равно хочется достичь схожего поведения класса TAutomobileи реального автомобиля. Именно из-за этого, наиболее интересной частью кода стал метод SetSpeed(), управляющий скоростью машины. Благодаря программной логике, заложенной в упомянутый метод (см. листинг5), мы не позволим набрать скорость автомобилю, если у него не включен двигатель. Предлагаю поставить перед собой еще одну задачу — при выключении двигателя скорость автомобиля должна упасть до 0.Если вы ненадолго вернетесь к листингу3, в котором представлены методы класса TEngine, то вы сразу вспомните, что за остановку двигателя отвечает процедура SetEnabled()с аргументом false. На первый взгляд, может показаться, что мы находимся в одном шаге от решения поставленной задачи — надо лишь дополнить метод SetEnabled()строкой кодаifValue=falsethenfAutomobile.fSpeed:=0;Однако на практике это невозможно. Причина проста— класс TEngineне имеет ни малейшего представления даже о существовании класса TAutomobile, не говоря уже о его полях и методах. Поэтому упоминание поля автомобиля fSpeedв методе двигателя приведет к одному— Delphi скажет, что идентификатор не объявлен (undeclared identifier) и откажется компилировать проект.Какой выход из создавшегося положения? Ответ таков: надо сделать так, чтобы двигатель знал, в какую машину он установлен. Для этого я введу в состав класса TEngineеще одно поле— fAutomobile:TAutomobile.Однако в нашем листингекласс TAutomobileобъявлен после класса TEngine, поэтому двигатель по-прежнему не понимает, что такое TAutomobile. Для устранения этой проблемы воспользуемся еще одной хитростью Delphi —опережающим объявлениемкласса.Суть идеи опережающего объявления заключается в том, что мы заявим о намерении описатькласс TAutomobileпрактически в первых строках листинга, а реальное описание оставим на прежнем месте (после описания двигателя). Благодаря такой уловке класс TEngineперестанет отвергать поле fAutomobile.Листинг3.8содержитусовершенствованноеобъявлениеклассовTEngineиTAutomobile.Листинг 3.8. Улучшенный способ объявления классов TEngine и TAutomobile
{началообъявлений,одноключевоесловоtypeдляTEngineиTAutomobile}typeTAutomobile=class;//опережающееобъявлениеклассаTAutomobile{полноеобъявлениеклассаTEngine}TEngine=class fEnabled:boolean;fAutomobile:TAutomobile;//автомобиль,вкоторыйустановлендвигатель//другиеполяиметодыклассаend;{полноеобъявлениеклассаTAutomobile} TAutomobile=class(TObject)fSpeed:single; //скоростьдвижения//другиеполяиметодыклассаend;Обязательно обратите внимание на небольшое изменение в порядке объявления классов. Раньше (см. листинги 3.2 и 3.3) описание каждого из классов начиналось с отдельного ключевого слова type, в новой версии кода для обеспечения видимости опережающего объявления класса TAutomobile
мы ограничились одним словом type.Еще одна синтаксическая особенность опережающего объявления в том, что заявление о существовании класса заканчивается не ключевым словом end, как того требует синтаксис (листинг 1). Вместо этого точка с запятой ставится сразу после инструкции class.Добившисьтого,чтоклассTEngineузналосуществованииклассаTAutomobile,усовершенствуем конструктор автомобиля (листинг 3.9).Листинг 3.9. Исправление конструктора класса TAutomobile
constructorTAutomobile.Create;beginfEngine:=TEngine.Create; //создаемдвигатель fEngine.fAutomobile:=self;//двигательполучилссылкунаавтомобиль fEngine.SetEnabled(False);//исходноесостояние—двигательвыключенend;Теперь,вмоментсозданияавтомобиля,ссылканаэкземплярклассаTAutomobileбудетпереданав соответствующее поле экземпляра класса TEngine. Благодаря ссылке двигатель получает возможность обращаться к полям и методам автомобиля.Намосталосьсделатьпоследнийштрих—дополнитьметодвключения/отключениядвигателяSetEnabled()командойнаостановкуавтомобиля(листинг3.10).Листинг 3.10. Остановка автомобиля в момент выключения двигателя
procedureTEngine.SetEnabled(Value:Boolean);beginfEnabled:=Value;ifValue=falsethenifAssigned(fAutomobile)then{еслиестьсвязанныйобъект} fAutomobile.fSpeed:=0;end;
Ограничение видимости членов класса
При описании класса программист имеет право определять степень доступности (видимости) его полей, свойств и методов. Это один из способов защиты наиболее критичных элементов класса от несанкционированного вмешательства сторонних разработчиков. Область видимости поля (метода) класса зависит от того, в какой из четырех возможных секций оно объявлено: private, protected,publicиpublished(листинг3.11).Листинг 3.11. Секции видимости членов классаtypeTAutomobile=class private...{секциячастныхобъявлений}protected...{секциязащищенныхобъявлений}public...{секцияобщихобъявлений}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. Объявление свойств
typeTEngine=class privatefEnabled:boolean;//двигательвключен-true,выключен-false fAutomobile:TAutomobile;//ссылканаавтомобильpublicprocedureSetEnabled(Value:Boolean);//запускилиостановдвигателяfunctionGetEngineState:boolean; //состояниедвигателяpublishedpropertyEnabled:booleanReadfEnabledWriteSetEnabled;propertyAutomobile:TAutomobileReadfAutomobile;end;Все поля класса "спрятаны" в секцию private, что существенно усложнит обращение к полям извне. Наоборот, методы и свойства, к которым мы намерены разрешить полный доступ, размещены в секции публичных объявлений. Теперь для включения/отключения двигателя надо воспользоваться