Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции Delphi (Колосов).pdf
Скачиваний:
77
Добавлен:
11.05.2015
Размер:
2.57 Mб
Скачать

объявить само событие, как свойство процедурного типа. В инспекторе объектов есть две страницы: страница свойств (Properties) и страница событий (Events). Двойной щелчок левой клавишей мыши по событию приводит к появлению обрамления обработчика события в тексте программного модуля

Unit.

Общими для всех компонентов являются события (наследники класса

TControl):

OnClick – нажатие левой клавиши мыши, OnDblClick – двойной щелчок левой клавиши мыши, OnMouseDown – нажатие любой клавиши мыши,

OnMouseMove – перемещение курсора мыши по компоненту, OnMouseUp – отжатие кнопки мышки.

Общими для оконных элементов управления являются события (наследники класса TWinControl):

OnEnter – перемещение фокуса ввода на компонент, который становится активным,

OnExit – потеря активности компонентом,

OnKeyDown – нажатие клавиши или комбинации клавиш, OnKeyPress – нажатие каждой одиночной клавиши,

On KeyUp – отпускание клавиши.

18. ВЫДЕЛЕНИЕ ПАМЯТИ ПОД ОБЪЕКТ И ПРАРОДИТЕЛЬ ВСЕХ КЛАССОВ – TOBJECT

18.1. Выделение памяти под объект

Рассмотрим более детально – что собой представляет объект? Допустим, что мы определили класс следующим образом:

Type TMyClass=Class

F1:Integer;

F2:String[20];

Procedure Sm1;

Procedure Vm1;virtual;

Procedure Vm2;virtual;

`Procedure Dm1;dynamic; Procedure Dm2;dynamic; End;

Вобработчике какого–то события в описании переменных определим указатель на объект класса TMyObject:

Var Obj1:TMyClass;

Вразделе действий мы создадим экземпляр этого объекта как

Obj1:=TMyClass.Create;

На рис.18.1 показано, как будет выглядеть внутренняя структура этого объекта.

84

 

Указатель на объект

 

Описание класса

 

Число

 

Obj1 (4 байта)

 

TMyObject

 

динамических

 

 

 

(RTTI)

 

методов (2)

 

 

 

 

 

Адрес метода

 

Индекс метода

 

 

 

TMyObject.VM1

 

TMyObject.DM1

 

 

 

Адрес метода

 

(-1)

 

Указатель на класс

 

TMyObject (4 байта)

 

TMyObject.VM2

 

Индекс метода

 

 

 

 

 

 

 

 

 

TMyObject.DM2

 

Поле F1 (4 байта)

 

 

 

 

 

 

 

 

(-2)

 

Поле F2 (21 байт)

 

 

 

 

 

 

 

 

Адрес метода

 

 

 

 

 

 

 

 

 

 

TMyObject.DM1

 

 

 

 

 

Адрес метода

 

 

 

 

 

TMyObject.DM2

Рис.18.1. Структура связи объекта с описаним класса Первое поле каждого экземпляра объекта содержит указатель на его

класс. Затем идут поля объекта в том порядке, как они описаны в классе, и всех наследуемых классах. Класс как структура состоит из двух частей. Указатель на класс определяет начало таблицы указателей на динамические методы класса. В эту таблицу включаются все наследуемые и вновь описанные в данном классе динамические методы. Перед таблицей динамических методов с отрицательным смещением располагается информация о классе, так называемая информация о типе времени выполнения (RunTime Type Information – RTTI). Описание этой информации можно найти в модуле System.pas (см. константы с приставкой vmt*). От версии к версии Delphi объем этой информации все возрастает и, например, для Delphi 6 составляет 76 байт. В этой области находятся 19 указателей на различные таблицы и параметры класса. Так, например, там есть указатели на классовые методы, которые можно вызывать, даже не выделяя объекту память, есть указатели на таблицы динамических методов, таблицу реализуемых интерфейсов (для совместимости с объектами COM) и т.д. Но к этой таблице напрямую нужно обращаться только в крайнем случае и имея большой опыт программирования на Delphi. Все основные параметры класса можно получать, используя методы прародителя всех классов класса TObject.

18.2. Описание класса TObject

Все описание класса TObject полностью наследуются остальными классами. Рассмотрим более подробно этот класс:

TObject = class

constructor Create; // Функция создания объекта. destructor Destroy; virtual; // Процедура разрушения объекта.

procedure Free; // Процедура освобождения памяти с предварительной // проверкой – а была ли ранее выделена память под объект?

85

// Классовая

class function InitInstance(Instance: Pointer): TObject; // Классовая функция,

//которая создает новый экземпляр объекта с занулением его полей и

//инициализации таблицы виртуальных методов. Эту функцию явно

//не вызывают, вместо нее для создания нового объекта вызывается

//метод NewInstance в конструкторе Create

class function NewInstance: TObject; virtual; // Классовая функция для

// создания нового объекта

procedure CleanupInstance; // Процедура освобождения памяти из–под

//длинных строк, переменных типа Variant и интерфейсов. Прямо ее

//не вызывают, она автоматически вызывается при вызове деструктора procedure FreeInstance; virtual; // Процедура освобождения памяти,

//выделенной ранее объекту методом NewInstance, она вызывается

//автоматически при вызове деструктора.

function ClassType: TClass; // Функция, возвращающая ссылку на класс. // Используется обычно в операторах is или as

class function ClassName: ShortString; // Классовая функция,

// возвращающая имя класса

class function ClassNameIs(const Name: string): Boolean;

//функция, проверяющая принадлежность объекта к классу с именем

//Name

class function ClassParent: TClass;

// Классовая функция, возвращающая

// указатель на родительский класс

 

class function ClassInfo: Pointer;

// Классовая функция, которая

// возвращает указатель на описание класса – область RTTI

class function InstanceSize: Longint;

// Классовая функция, которая

// возвращает длину объекта в байтах

class function InheritsFrom(AClass: TClass): Boolean; // Классовая

//функция для проверки условия – является ли данный класс

//наследником класса AClass

class function MethodAddress(const Name: ShortString): Pointer;

//Классовая функция, которая возвращает указатель на метод с именем

//Name

class function MethodName(Address: Pointer): ShortString;

// Классовая

// функция, которая возвращает имя метода по его адресу

 

function FieldAddress(const Name: ShortString): Pointer;

// Классовая

// функция, которая возвращает указатель на поле с именем Name

function GetInterface(const IID: TGUID; out Obj): Boolean;

// Функция

//получения указателя на интерфейс с глобальным идентификатором IID.

//Если такой интерфейс присутствует в системе, то эта функция

//возвращает истину

class function GetInterfaceEntry(const IID: TGUID): PInterfaceEntry;

//Классовая функция получения указателя на интерфейс с глобальным

//идентификатором IID

class function GetInterfaceTable: PInterfaceTable; // Классовая

// функция получения указателя на начало таблицы интерфейсов

86

function SafeCallException(ExceptObject: TObject;

ExceptAddr: Pointer): HResult; virtual; // Функция получения указателя

//на процедуру обработки исключительной ситуации, используя SafeCall

//соглашение при вызове подпрограмм

procedure AfterConstruction; virtual; // Метод, который будет вызываться

// после создания объекта

procedure BeforeDestruction; virtual; // Метод, который будет вызываться

// перед разрушениям объекта

procedure Dispatch(var Message); virtual; // Процедура диспетчеризации

//вызовов динамических методов c помощью Windows сообщений procedure DefaultHandler(var Message); virtual; // Обработчик Windows

//сообщений по умолчанию

end;

Как видно из этого описания, большинство методов этого класса – классовые методы и их можно вызывать, даже не создав ни одного объекта, так как информация о классе создается еще на этапе проектирования проекта.

18.3.Операторы приведения типов классов

Вобработчики событий обычно первым параметром передается источник события Sender с типом TObject. На самом деле Sender может соответствовать любому объекту, например форме или другому компоненту. Поэтому, чтобы использовать их свойства и методы, следует использовать оператор As, например:

(Sender as TEdit).Text:=’Начальное значение’;

Оператор As используется для приведения объектных типов, причем производится проверка на совместимость типов во время выполнения программы. Попытка приведения несовместных типов приводит к исключительной ситуации – EInvalidCast. После применения оператора As сам объект остается неизменным, но можно вызывать его методы, которые соответствуют присваиваемому классу.

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

например: If Form1 is TForm then ……. Else ………..;

Эта проверка осуществляется еще на этапе компиляции и, если формально объект и класс несовместимы, выдается сообщение об ошибке в таком операторе.

19.ОБРАБОТКА ИСКЛЮЧИТЕЛЬНЫХ СИТУАЦИЙ

19.1. Два вида оператора Try

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

87

выводит окно с сообщением об ошибке, и выполнение программы на этом заканчивается. Но иногда программист хочет сам обработать такие исключительные ситуации и принять решение о дальнейшем направлении выполнения программы. В Delphi это можно сделать несколькими способами. Например, как это было показано в лекции по работе с файлами, можно отключить стандартную обработку ошибок ввода–вывода вставкой в текст программы оператора {$I-}. Затем выполняются любые действия с файлами и проверяется код ошибки с помощью функции IOResult. Если он отличен от нуля, то можно проанализировать эту ошибку и принять какое–то решение. Затем можно опять включить стандартную отработку ошибок ввода–вывода оператором {$I+}. Можно также анализировать ситуацию до появления возможной ошибки с помощью операторов If и принимать какие–то решения до возникновения исключительной ситуации. Но все эти способы в настоящее время используются очень редко. В Delphi есть специальный оператор для защиты кода от исключительных ситуаций – это оператор

Try

{Защищаемый код }

Finally

{Операторы завершения защищаемого кода}

End;

и вторая его модификация:

Try

{Защищаемый код}

Except

On Exception1 Do Оператор1: On Exception1 Do Оператор2;

……………

else

{Операторы для всех остальных исключительных ситуаций} end;

Для первого варианта оператора Try в любом случае, произошла ли исключительная ситуация или нет, все равно выполняются операторы из секции Finally. Во втором варианте оператора Try при возникновении исключительной ситуации можно предусмотреть отдельную обработку любой из таких ситуаций. Для всех остальных исключительных ситуаций, для которых не предусмотрена отдельная обработка, будут выполняться операторы, следующие за ключевым словом Else. Чем же отличаются исключительные ситуации? Поскольку это объекты, то они отличаются классом или объектным типом. Объектный тип Exception описан в модуле SysUtils.pas. Этот класс является родительским для многочисленных дочерних классов, которые соответствуют различным исключительным ситуациям. Все имена потомков этого класса начинаются с буквы E, например, класс EZeroDevide – соответствует исключительной ситуации деления на ноль, а класс EInOutError – ошибке ввода–вывода. В последнем классе есть поле ErrorCode, которое определяет код

88