Конспект лекций по дисциплине «Высокоуровневые методы информатики и программирования» для студентов специальности 080801 «Прикладная информатика в экономике»
Вид материала | Конспект |
- Темы курсовых работ по дисциплине «Высокоуровневые методы информатики и программирования», 82.9kb.
- Рабочая программа по дисциплине: «высокоуровневые методы информатики и программирования», 127.42kb.
- Курс Методы визуального программирования при разработке системного программного обеспечения., 30.14kb.
- Учебно-методический комплекс «Высокоуровневые методы информатики и программирования», 569.1kb.
- Рабочая программа по дисциплине «Исследование операций в экономике» для специальности, 137.37kb.
- Рабочая программа по дисциплине "Имитационное моделирование экономических процессов", 207.47kb.
- Рабочая программа по дисциплине «Математическая экономика» для специальности 080801, 222.52kb.
- Рабочая программа по дисциплине "Технико-экономический анализ деятельности предприятий", 356.09kb.
- Рабочая программа по дисциплине "Финансы и кредит" Для специальности 080801 Прикладная, 181.17kb.
- Рабочая программа по дисциплине "алгоритмизация и программирование" для специальности, 136.39kb.
Обработка исключений
Во время выполнения программы могут возникнуть ситуации, в результате которых может быть нарушена работа программы: обращение к несуществующему файлу или устройству, ошибка «деление на нуль», обращение по несуществующему адресу и т.д. Причиной таких аварийных ситуаций могут стать как некорректные действия пользователя, так и ошибки в самой программе.
Стандартные действия системы в ответ на обнаружение подобной ситуации заключаются в аварийном завершении программы с фиксацией причины в виде кода ошибки. Разработчики программного обеспечения должны максимально предусматривать возможность возникновения аварийных ситуаций, чтобы их появление не приводило к нарушению работы программы. Этой цели посвящается существенная доля всех операторов программы.
Delphi предлагает специальный механизм управления аварийными ситуациями, который позволяет «перехватить» аварийное завершение программы, определить его причину и далее, либо устранить аварийную ситуацию и продолжить работу, либо завершить работу системы с выдачей полной информации об ошибке и сохранением всех данных. Этот механизм реализуется через средства обработки исключений.
В основе механизма обработки исключений лежит автоматическое формирование специального блока информации при обнаружении аварийной ситуации. Доступ к этому блоку осуществляется через объект специального класса, наследуемого от базового класса всех исключений Exception.
Сравним обычный подход и подход, предполагающий использование исключений на примере обработки возможной ошибки «деление на ноль».
Традиционный подход | Использование исключений |
if n<>0 then x:=A/n else <действия по устранению ошибки > | try x:=A/n; except on EDivByZero do <действия по устранению ошибки > end; |
Сравнение показывает, что в отличие от традиционного подхода, при использовании исключений действия по обработке аварийной ситуации не включаются в основной алгоритм, а группируются в своей секции специальной конструкции. Кроме того, существует гарантия перехвата аварийной ситуации, тогда как при использовании традиционного подхода такой гарантии нет. Последнее связано с тем, что ситуация «деление на нуль» фиксируется схемами контроля микропроцессора при переполнении регистра результата, что может произойти и просто при большом значении делимого и маленьком значении делителя.
Механизм обработки исключений органично вписывается в ООП, позволяя реализовывать обработку исключений в разрабатываемых классах.
К средствам обработки исключений относятся:
- специальные конструкции языка для разделения операторов основной части программы и операторов обработки исключений,
- иерархия классов различных исключений, определенная в Delphi;
- оператор генерации исключения;
- операторы обработки исключений.
^ Структура фрагментов с исключениями. Фрагменты программ, использующих исключения, оформляются с использованием двух специальных конструкций try …finally и try … except, которые определяются следующим образом:
try <операторы, при выполнении которых могут возникнуть исключения> finally <операторы, которые выполняются после предыдущих или при возникновении исключения> end; | try <операторы, при выполнении которых могут возникнуть исключения> except <операторы, которые выполняются только при возникновении исключения> end; |
Использование этих конструкций позволяет выделить операторы обработки исключений в особые группы.
Первая конструкция используется, если необходимо определить группу операторов, которые должны завершить выполнение какой-либо обработки не зависимо от того, будет сформировано исключение или нет. Например, чтобы закрыть открытые файлы или удалить с экрана форму.
Вторая конструкция используется, если при возникновении исключения необходимо выполнить специальные действия, которые аннулируют последствия возникновения исключительной ситуации.
Конструкции перехвата исключений могут быть вложены одна в другую в любом порядке.
^ Создание исключений. Базовым классом для всех исключений является класс Exception. Этот класс предусматривает достаточно большое количество конструкторов, которые формируют объекты различной структуры. Основные свойства класса Exception - свойства Сообщение и Контекст помощи. В Delphi 4 класс этот класс описывается следующим образом:
^ Type Exception = class(TObject)
private
FMessage: string;
FHelpContext: Integer;
public
Constructor Create(const Msg: string);{объект содержит сообщение, заданное строкой}
Constructor CreateFmt(const Msg: string;
const Args: array of const); { объект содержит сообщение, заданное строкой, дополненной форматируемыми параметрами}
^ Constructor CreateRes(Ident: Integer; Dummy: Extended = 0); {объект содержит сообщение, получаемое из файла ресурса по его идентификатору}
Constructor CreateResFmt(Ident: Integer;
const Args: array of const); {объект содержит сообщение, получаемое из файла ресурса по его идентификатору, причем строка сообщения может дополняться форматируемыми параметрами}
^ Constructor CreateHelp(const Msg: string; AHelpContext: Integer); {объект содержит сообщение и контекст помощи}
Constructor CreateFmtHelp(const Msg: string;
const Args: array of const; AHelpContext: Integer); {объект содержит сообщение с форматируемыми параметрами и контекст помощи }
^ Constructor CreateResHelp(Ident: Integer; AHelpContext: Integer); {объект содержит сообщение, получаемое из файла ресурса, и контекст помощи}
Constructor CreateResFmtHelp(Ident: Integer;
const Args: array of const; AHelpContext: Integer); { объект содержит сообщение с форматируемыми параметрами, получаемое из файла ресурса, и контекст помощи }
property HelpContext: Integer
read FHelpContext write FHelpContext; {контекст помощи}
property Message: string read FMessage write FMessage; {строка сообщения}
end;
Основное назначение класса исключения - идентификация групп ошибок: отнесение исключения к тому или другому классу определяет способ обработки данного исключения (см. далее).
Потомками класса Exception являются, например, следующие классы исключений:
EDivByZero = class(EIntError); {деление на ноль в целочисленной арифметике}
ERangeError = class(EIntError); {обращение элементам массива по несуществующим индексам}
EIntOverflow = class(EIntError); {переполнение в целочисленной арифметике}
EMathError = class(EExternal); {ошибки арифметики с плавающей точкой}
EInvalidOp = class(EMathError); {неверный операнд)
EZeroDivide = class(EMathError); {деление на ноль в арифметике с плавающей точкой}
EOverflow = class(EMathError); {переполнение в арифметике с плавающей точкой}
EUnderflow = class(EMathError); {исчезновение порядка в арифметике с плавающей точкой}
При необходимости разработчик может определить собственные исключения, наследуя их от соответствующего класса. Желательно, чтобы имена исключений, создаваемых разработчиком начинались с буквы «E».
^ Генерация исключений. Исключения могут генерироваться автоматически (при обнаружении той или иной аварийной ситуации операционной системой) и программно (по мере надобности). Для программной генерации исключений используется специальный оператор raise, за которым обычно следует вызов одного из конструкторов класса-исключения, например:
if n=0 then raise EDivByZero.Create('Количество отрезков равно 0.');
В приведенном примере генерируется исключение класса EDivByZero. При этом конструируется специальный объект, особенностью которого является отсутствие идентификатора. Память под этот объект отводится системой автоматически.
^ Обработка исключений. Обработка исключений выполняется в секции except конструкции try … except с помощью специальной конструкции типа case:
except
on <тип исключения> do <оператор>;
on <тип исключения> do <оператор>;
. . .
on <тип исключения> do <оператор>;
else <оператор>
end;
Таким образом, для каждого типа исключения может быть предусмотрена своя обработка.
Поскольку объекты исключений создаются без имени, существуют специальные способы организации доступа к полям и методам объекта-исключения.
1 способ. Можно использовать формальную переменную, которая связывается с объектом-исключением уже в процессе обработки. Эта переменная описывается только внутри варианта on и доступна также только внутри одной альтернативы:
try . . .
except
on E:EDivByZero do {объявление переменной с указанием типа}
begin
<переменная E доступна и может использоваться для обращения к полям и методам объекта, например, E.Message>
end;
else <переменная E – не доступна>
end;
2 способ. Можно использовать функцию
function ExceptionObject:TObject;
Эта функция возвращает объектную ссылку на текущее исключение, при отсутствии исключений она возвращает nil:
try <контролируемые действия>
except
on EDivByZero do
ShowMessage(EDivByZero(ExceptionObject).Message); {используется явное преобразование типов}
end;
Если используется вложение конструкций try … except, то можно перепоручить обработку исключения секции except внешней конструкции, указав в секции except внутренней конструкции оператор raise:
try . . .
try . . .
except
on <тип исключения> do <оператор>;
. . .
else raise;
end
except
<обработка остальных исключений>
end;
Возможны ситуации, когда необходимо знать адрес фрагмента, при выполнении которого фиксируется аварийная ситуация. С этой целью можно использовать специальную переменную
var ErrorAddr: Pointer
При генерации исключения для помещения адреса ошибки в это поле используется конструкция raise … at …, например:
raise Exception.Create('Исключение с адресом') at ErrorAddr;
Пример 3.42. Использование исключений (класс «Динамический массив» - вариант 2)
Проиллюстрируем использование исключений на примере разработки класса «Динамический массив», рассмотренном в примере 5.4.
Для того чтобы данный класс можно было безопасно использовать в приложениях, необходимо предусмотреть в нем обработку аварийных ситуаций. Такая обработка предусматривалась в примере по традиционной схеме. Используем с той же целью исключения.
Анализ алгоритмов методов данного класса позволяет определить, что при использовании объектов данного класса могут возникнуть следующие аварийные ситуации:
1) попытка записать элемент за пределами выделенной памяти;
2) попытка обращения (чтения) или записи элемента за пределами используемой части массива, за исключением добавления элемента за последним;
3) попытка преобразовать в число пустую строку или строку, содержащую недопустимые элементы.
Эти ситуации будут обнаружены в трех методах: в методе SetEl, в методе GetEl и в методе InputMas.
Соответственно, описываем в модуле новые исключения и генерируем их вышеуказанных методах:
^ Unit MasByte;
Interface
Uuses SysUtils,Dialogs, Grids;
Type
TMas=array[1..255] of byte;
TMasByte = class(TObject)
private
ptr_an: ^TMas; {указатель на массив}
len:byte; {максимальная длина массива}
Name:string;{для выдачи диагностики будем хранить имя объекта}
^ Procedure SetEl(Ind:byte;m:byte);
Function GetEl(Ind:byte):byte;
public
n:Byte; {реальный размер массива}
Constructor Create(an:byte;aName:string);
Destructor Destroy;override;
Property Mas[Ind: byte]:byte read GetEl write SetEl;default;
Procedure Modify(Ind:byte;Value:byte);
Procedure Insert(Ind:byte;Value:byte);
Function Delete(Ind:byte):byte;
Function InputMas(Grid:TStringGrid;I,J:integer):boolean;
Procedure OutputMas(Grid:TStringGrid;I,J:integer);
end;
EInputError=class(Exception);{дополнительное исключение}
Implementation
Constructor TMasByte.Create;
Begin
inherited Create;
GetMem(ptr_an,an);
len:=an; Name:=aName;
End;
Destructor TMasByte.Destroy;
Begin
FreeMem(ptr_an);
inherited Destroy;
End;
Procedure TMasByte.SetEl(Ind:byte;m:byte);
Begin
if Ind<=len then
if Ind<=n then ptr_an^[Ind]:=m
else
raise ERangeError.CreateFmt('В массиве %s нет %d-го элемента.',[Name,Ind]) {генерация исключения}
else
raise ERangeError.CreateFmt('В массиве %s можно разместить только %d элементов.',[Name,Len]); {генерация исключения}
End;
^ Function TMasByte.GetEl(Ind:byte):byte;
Begin
if Ind<=n then Result:=ptr_an^[Ind]
else
raise ERangeError.CreateFmt('В массиве %s нет %d-го элемента.', [Name,Ind]); {генерация исключения}
End;
Function TMasByte.InputMas(Grid:TStringGrid;I,J:integer):boolean;
Var k:byte; x,er_code:integer;
Begin
with Grid do
begin
k:=0;
Result:=true;
while (Cells[k+I,J]<>'')and Result do
begin
Val(Cells[k+I,J],x,er_code);
if er_code=0 then
if x<=255 then Insert(k+1,x)
else
begin
raise EInputError.Create('Значение не может превышать 255.'); {генерация исключения}
Result:=false;
exit;
end
else
begin
raise EInputError.Create('В строке обнаружены недопустимые символы.'); {генерация исключения}
Result:=false;
exit;
end;
k:=k+1;
end;
OutputMas(Grid,I,J);
end;
End;
. . . {тексты остальных методов не изменились}
end.
Теперь при работе с объектами данного класса следует предусматривать обработку исключений, которые могут быть генерированы в процессе выполнения.
Например, вызов функции ввода элементов теперь должен выглядеть следующим образом:
A:=TMasByte.Create(10,'A'); {конструируем объект A}
try A.InputMas(StringGrid,0,0);{пробуем ввести массив}
except
on E:EInputError do {если обнаружено исключение ввода}
MessageDlg(E.Message,mtInformation,[mbOk],0);
end;
Аналогично, при попытке записать что-либо в массив следует предусматривать возможность возникновения аварийной ситуации:
try A[Ind]:=Value; {пробуем занести значение в массив}
except
on E:ERangeError do {если обнаружено исключение «неверный индекс»)
MessageDlg(E.Message,mtInformation, [mbOk], 0);
end;
Вопросы к главе 5
- Дайте определение класса, принятое в Delphi Pascal. Какие новые возможности определения классов появились в этом языке программирования по сравнению с Pascal 7.0? Сравните их с аналогичными средствами, существующими в С++3.1?
- Какие виды полиморфизма реализованы в данной среде? Дайте определение абстрактным и динамическим методам? Поясните, чем они отличаются от обычных виртуальных методов. Определите сущность перегрузки методов.
- Определите понятие «свойство». С какой целью целесообразно использовать механизм свойств? Приведите примеры.
- Что такое «информация о типе времени выполнения»? Зачем она используется? Дайте определение метакласса и поясните, для чего он может быть использован. Какую роль играют методы класса и почему их можно вызывать без указания имени объекта?
- Поясните сущность понятия «делегирование методов». Какие средства должен включать язык, в котором возможна реализация делегирования?
- Как построена библиотека VCL? Чем различаются отношения «основной/вспомогательный» и «старший/младший»? Как их можно использовать?
- Какие средства создания сообщений предлагаются средой Delphi? В каких случаях возникает необходимость создания новых сообщений? Как описывается обработчик сообщений? Как генерировать новые события?
- Какие ситуации попадают под понятие «исключительные»? Почему возникла необходимость создания средств обработки исключений? Поясните процесс создания/обработки исключений. Перечислите средства, позволяющие реализовать данный процесс.