Var B:byte; W:word; L:LongInt;
то можно записать:
L:=LongInt(W); B:=ByteRec(W).Lo;
ByteRec(W).Hi:=0; W:=WordRec(L).Lo;
B:=ByteRec(WordRec(L).Lo).Hi;
К специальным подпрограммам преобразования типов относится множество подпрограмм, которые были использованы в программах выше (Ord, IntToStr, StrToInt, Chr, FloatToStr, StrToFloat и др.).
ОПЕРАТОРЫ ОБРАБОТКИ ИСКЛЮЧИТЕЛЬНЫХ СИТУАЦИЙ
Когда возникает исключительная ситуация, то, независимо от её источника, программа узнает о ней. Компилятор создаёт код, который в состоянии прервать выполнение программы. После прерывания из стека, содержащего локальные переменные, начинают “выталкиваться” данные. Процесс “выталкивания” данных продолжается до тех пор, пока не произойдёт одно из двух событий:
1. Выполнение программы дойдёт до операторов локальной обработки исключительной ситуации;
2. Управление будет передано встроенному глобальному обработчику исключительной ситуации.
Приложение в большинстве случаев должно содержать программные фрагменты, предназначенные для обработки возникающих исключительных ситуаций, в том числе и для управления работой стека. Как было отмечено выше, при возникновении исключительной ситуации создаётся объект обработки ошибки, остающийся в памяти до тех пор, пока он не будет оттуда удалён.
В любом приложении, основанном на VCL, имеется глобальная переменная Application, являющаяся экземпляром класса TApplication. Этот класс определён в модуле Forms и объединяет в себе все автоматически создающиеся формы программы. Объект Application выполняет множество функций. Одна из них – обеспечение по умолчанию глобального механизма обработки исключительных ситуаций. Как только произойдёт исключительная ситуация, объект Application генерирует событие OnException. Событию TApplication.OnExceptionможно назначить собственный обработчик. Этот процесс называется делегированием событий. Если никакая процедура не назначена, то событие OnException вызывает стандартный обработчик.
Наряду с механизмом делегирования программную обработку ошибок можно осуществлять с помощью специальных операторов. Для этих целей оределены две конструкции: Try…finally и Try…except. Они совершенно аналогичны по синтаксису, но различаются по назначению. Конструкция Try…finally имеет следующий синтаксис:
Try <операторы> finally <операторы> End;
Если в любом из операторов, размещённых между Try…finally возникает исключительная ситуация, их выполнение прекращается и управление передаётся первому оператору, следующему за ключевым словом finally. После этого выполняются все операторы, стоящие между finally и End (операторы, стоящие между finally и end выполняются и тогда, если ошибки не произошло).
Конструкция Try…finally применяется для довольно длительного перехвата исключительной ситуации, чтобы выполнить все полагающиеся перед завершением программы действия, прежде чем управление будет передано глобальному обработчику исключительных ситуаций или следующему уровню обработки ошибки. Эта конструкция не удаляет экземпляра объекта обработки исключительной ситуации, и, таким образом, не обрабатывает ошибки, а только сообщает о ней.
Конструкция Try…except применяется для перехвата исключительной ситуации с последующей возможной обработкой, предусматривающей освобождение экземпляра объекта обработки исключительной ситуации, после чего выполнение программы продолжается далее, что и отличает, главным образом, оператор Try…except от Try…finally. В этой конструкции есть необязательный дополнительный элемент, с помощью которого можно определить фактический тип возникшей исключительной ситуации, - элемент вида on…do:
Try
<операторы>
Except
on E: Exception do <оператор>
on E: Exception do <оператор>
. . . . . . . . . . . . . .
else <оператор>
End;
После ключевого слова elseчасто следует ключевое слово Raise, которое переводит обработку ошибки на новый уровень (разрешается создавать вложенные блоки Try), например, на уровень глобального обработчика. Raise прерывает программу и выталкивает данные из стека. Однако, если будет записано Raise <процедура>, где процедура позволяет создать собственное исключение, то выталкивания данных из стека не последует (если только внутри процедуры не возникнет ошибки). Процедура, записываемая после Raise, должна быть особого вида – она должна быть конструктором, - так как она должна создать объект какого-либо класса исключений.
В заключение отметим, что блок от Try до Finally(или до Except) называется блоком защиты ресурсов, а последующий блок до End – блоком очистки.
ПРИМЕР 11
Построить график функции Y = 1/ln(X). (Методика построения графиков приводится при описании примера 4). Данная функция обладает рядом особенностей, которые как раз удобно использовать для иллюстрации исключений. Во-первых, функция не определена при отрицательных значениях аргумента. Во-вторых, она не определена при X = 1 (деление на нуль). Для всех особых точек, естественно, отображать график не будем. Вариант решения задачи приводится на рис. 31.
Рис. 31 Вариант решения примера 11.
Для демонстрации рассматриваемых выше операторов воспользуемся методикой создания собственных исключений. Введём собственный тип - класс ErangeError=class(EmathError);, - являющийся наследником встроенного класса EmathError. Используя ключевое слово Raise, создадим два исключения: одно – ErangeError – для фиксации случая отрицательного аргумента, а другое – переопределим стандартное EDivByZero. Если в программе встретятся другие исключения, то они будут обрабатываться стандартно – в программе эти ситуации определяются просто ключевым словом Raise. Программа для решения примера 11 приводится ниже.
unit prim11;
Interface
uses Windows, Messages, SysUtils, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls, Buttons, ExtCtrls;
Type
TForm1 = class(TForm)
Panel1: TPanel;
Button1: TButton;
BitBtn1: TBitBtn;
Edit1: TEdit;
Label1: TLabel;
Edit2: TEdit;
Label2: TLabel;
Image1: TImage;
Label3: TLabel;
Procedure Edit1KeyPress
(Sender: TObject; var Key: Char);
procedure Button1Click(Sender: TObject);
end;
ERangeError = class(EMathError);
var Form1: TForm1;
Implementation
{$R *.DFM}