Файл: Лр операторы и выражения Delphi.doc

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 10.01.2024

Просмотров: 307

Скачиваний: 1

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

СОДЕРЖАНИЕ

ЛР 1. Операторы и выражения Delphi

Оператор присваивания

Арифметические операторы

Оператор конкатенации строк

Логические операторы

Операторы поразрядного сдвига

Операторы отношения

Операторы множеств

Оператор-селектор case

Оператор перехода goto

Организация циклов

ЛР 2. Структурные типы

Множества

Записи

Массивы

ЛР 3. Объекты и классы

Проектирование класса

Управление жизненным циклом объекта

Опережающее объявление класса

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

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

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

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

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

Полиморфизм

ЗАДАНИЕ

ЛР4. Опорные классы VCL

Класс TControl

Принадлежность к родительскому контейнеру

Размещение и размеры элемента управления

Видимость и активность элемента управления

Задание

ЛР5. Обработка клавиатурных событий и событий мышки

Щелчки кнопками мыши

Перемещение указателя мыши

Вращение колесика мыши

Операция перетаскивания drag and drop

Задание

ЛР 6. Классы потоков данных

Прототип потоков данных, класс TStream

, то создание и уничтожение объекта будет осуществлено за счет конструктора и деструктора родительского класса. В нашем примере мы не стали создавать индивидуальные методы 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() строкой кода

if Value=false then fAutomobile.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}

type

TAutomobile=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




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

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

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, что существенно усложнит обращение к полям извне. Наоборот, методы и свойства, к которым мы намерены разрешить полный доступ, размещены в секции публичных объявлений. Теперь для включения/отключения двигателя надо воспользоваться