Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование на языке Delphi_2.doc
Скачиваний:
31
Добавлен:
28.03.2015
Размер:
494.59 Кб
Скачать

3.8.3. Абстрактные виртуальные методы

При построении иерархии классов часто возникает ситуация, когда работа виртуального метода в базовом классе не известна и наполняется содержанием только в наследниках. Так случилось, например, с методом Draw, тело которого в классе TFigure объявлено пустым. Конечно, тело метода всегда можно сделать пустым или почти пустым (так мы и поступили), но лучше воспользоваться директивой abstract:

Type

TFigure = class

procedure Draw; virtual; abstract;

end;

Директива abstract записывается после слова virtual и исключает необходимость написания кода виртуального метода для данного класса. Такой метод называется абстрактным, т.е. подразумевает логическое действие, а не конкретный способ его реализации. Абстрактные виртуальные методы часто используются при создании классов-полуфабрикатов. Свою реализацию такие методы получают в законченных наследниках.

3.8.4. Динамические методы

Разновидностью виртуальных методов являются так называемые динамические методы.

1. При их объявлении вместо ключевого слова virtual записывается ключевое слово dynamic.

2. В наследниках динамические методы перекрываются так же, как и виртуальные — с помощью зарезервированного слова override.

3. По смыслу динамические и виртуальные методы идентичны. Различие состоит только в механизме их вызова. Методы, объявленные с директивой virtual, вызываются максимально быстро, но платой за это является большой размер системных таблиц, с помощью которых определяются их адреса. Размер этих таблиц начинает сказываться с увеличением числа классов в иерархии.

4. Методы, объявленные с директивой dynamic вызываются несколько дольше, но при этом таблицы с адресами методов имеют более компактный вид, что способствует экономии памяти. Таким образом, программисту предоставляются два способа оптимизации объектов: по скорости работы (virtual) или по объему памяти (dynamic).

3.8.5. Методы обработки сообщений

Специализированной формой динамических методов являются методы обработки сообщений. Они объявляются с помощью ключевого слова message, за которым следует целочисленная константа — номер сообщения. Следующий пример взят из исходных текстов библиотеки VCL:

type

TWidgetControl = class(TControl)

...

procedure CMKeyDown(var Msg: TCMKeyDown); message CM_KEYDOWN;

...

end;

Метод обработки сообщений имеет формат процедуры и содержит единственный var-параметр. При перекрытии такого метода название метода и имя параметра могут быть любыми, важно лишь, чтобы неизменным остался номер сообщения, используемый для вызова метода. Вызов метода выполняется не по имени, как обычно, а с помощью обращения к специальному методу Dispatch, который имеется в каждом классе (метод Dispatch определен в классе TObject).

Методы обработки сообщений применяются внутри библиотеки VCL для обработки команд пользовательского интерфейса и редко нужны при написании прикладных программ.

3.9. Указатели на методы объектов

Мы уже говорили о процедурном типе. Переменная процедурного типа – это указатель на адрес процедуры или функции. Если же мы хотим сделать ссылку не просто на процедуру или функцию, а на метод объекта, то мы должны добавить ключевое словосочетание of object, записанное после прототипа процедуры или функции:

type

TMethod = procedure of object;

TNotifyEvent = procedure(Sender: TObject) of object;

Переменная такого типа называется указателем на метод (method pointer). Она занимает в памяти 8 байт и хранит одновременно ссылку на объект и адрес его метода (получается, на самом деле 2 указателя). Например:

type

TNotifyEvent = procedure(Sender: TObject) of object;

TMainForm = class(TForm)

procedure ButtonClick(Sender: TObject);

...

end;

var

MainForm: TMainForm;

OnClick: TNotifyEvent

Тогда можно сделать следующую привязку:

OnClick := MainForm.ButtonClick;

Используя переменные типа указателя на метод можно описывать события. Рассмотрим пример с использованием ранее описанного класса TFigure.

Type

TFigure = class

private

FOnDraw: TNotifyEvent;

public

property OnDraw: TNotifyEvent read FOnDraw write FOnDraw;

end;

и в методе Draw:

procedure TFigure.Draw;

begin

... //рисуем фигурку

if Assigned(FOnDraw) then

FOnDraw(Self); //уведомление о рисовании фигурки

end;

end;

Обратите внимание, что вызов метода через указатель происходит лишь в том случае, если указатель не равен nil. Эта проверка выполняется с помощью стандартной функции Assigned, которая возвращает True, если ее аргумент является связанным указателем.

Описанный выше механизм называется делегированием, поскольку он позволяет передать часть работы другому объекту, например, сосредоточить в одном объекте обработку событий, возникающих в других объектах. Это избавляет программиста от необходимости порождать многочисленные классы-наследники и перекрывать в них виртуальные методы. Делегирование широко применяется в среде Delphi. Например, все компоненты делегируют обработку своих событий той форме, в которую они помещены.