Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
delphi.pdf
Скачиваний:
191
Добавлен:
24.02.2016
Размер:
6.84 Mб
Скачать

По смыслу динамические и виртуальные методы идентичны. Различие состоит только в механизме их вызова. Методы, объявленные с директивой virtual, вызываются максимально быстро, но платой за это является большой размер системных таблиц, с помощью которых определяются их адреса. Размер этих таблиц начинает сказываться с увеличением числа классов в иерархии. Методы, объявленные с директивой 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. Классы в программных модулях

Классы очень удобно собирать в модули. При этом их описание помещается в секцию interface, а код методов — в секцию implementation. Создавая модули классов, нужно придерживаться следующих правил:

189

все классы, предназначенные для использования за пределами модуля, следует определять в секции interface;

описание классов, предназначенных для употребления внутри модуля, следует располагать в секции implementation;

если модуль B использует модуль A, то в модуле B можно определять классы, порожденные от классов модуля A.

Соберем рассмотренные ранее классы TTextReader, TDelimitedReader и TFixedReader в отдельный модуль ReadersUnit:

unit ReadersUnit;

interface

type

TTextReader = class private

// Поля

FFile: TextFile;

FItems: array of string; FActive: Boolean;

// Методы

procedure PutItem(Index: Integer; const Item: string); // Методы чтения и записи свойств

procedure SetActive(const AActive: Boolean); function GetItemCount: Integer;

function GetEndOfFile: Boolean; protected

//Методы чтения и записи свойств function GetItem(Index: Integer): string;

//Абстрактные методы

function ParseLine(const Line: string): Integer; virtual; abstract; public

// Конструкторы и деструкторы

constructor Create(const FileName: string); destructor Destroy; override;

// Методы

function NextLine: Boolean; // Свойства

property Active: Boolean read FActive write SetActive; property Items[Index: Integer]: string read GetItem; default; property ItemCount: Integer read GetItemCount;

property EndOfFile: Boolean read GetEndOfFile; end;

TDelimitedReader = class(TTextReader) private

// Поля

FDelimiter: Char; protected

// Методы

190

function ParseLine(const Line: string): Integer; override; public

// Конструкторы и деструкторы

constructor Create(const FileName: string; const ADelimiter: Char = ';');

// Свойства

property Delimiter: Char read FDelimiter; end;

TFixedReader = class(TTextReader) private

// Поля

FItemWidths: array of Integer; protected

// Методы

function ParseLine(const Line: string): Integer; override; public

// Конструкторы и деструкторы

constructor Create(const FileName: string; const AItemWidths: array of Integer);

end;

TMyReader = class(TDelimitedReader)

property FirstName: string index 0 read GetItem; property LastName: string index 1 read GetItem; property Phone: string index 2 read GetItem;

end;

implementation

{ TTextReader }

constructor TTextReader.Create(const FileName: string); begin

inherited Create; AssignFile(FFile, FileName); FActive := False;

end;

destructor TTextReader.Destroy; begin

Active := False; inherited;

end;

function TTextReader.GetEndOfFile: Boolean; begin

Result := Eof(FFile); end;

function TTextReader.GetItem(Index: Integer): string; begin

Result := FItems[Index]; end;

191

function TTextReader.GetItemCount: Integer; begin

Result := Length(FItems); end;

function TTextReader.NextLine: Boolean;

var

 

 

S: string;

 

 

N: Integer;

 

 

begin

 

 

Result := not EndOfFile;

// Если не достигнут конец файла

if Result then

begin

// Чтение очередной строки из файла

Readln(FFile, S);

N := ParseLine(S);

// Разбор считанной строки

if N <> ItemCount then

// Отсечение массива (если необходимо)

SetLength(FItems, N);

end;

 

 

end;

 

 

procedure TTextReader.PutItem(Index: Integer; const Item: string);

begin

 

// Если индекс выходит за границы

if Index > High(FItems) then

массива,

SetLength(FItems, Index + 1); // то увеличение размера массива

FItems[Index] := Item;

// Установка соответствующего элемента

end;

 

procedure TTextReader.SetActive(const AActive: Boolean); begin

if Active <> AActive then // Если состояние изменяется begin

if AActive then

// Открытие файла

Reset(FFile)

else

// Закрытие файла

CloseFile(FFile);

FActive := AActive;

// Сохранение состояния в поле

end;

 

end;

 

{ TDelimitedReader }

 

constructor TDelimitedReader.Create(const FileName: string; const ADelimiter: Char = ';');

begin

inherited Create(FileName); FDelimiter := ADelimiter;

end;

function TDelimitedReader.ParseLine(const Line: string): Integer; var

S: string; P: Integer;

192

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]