На этом шаге мы рассмотрим правила обработки исключений.
Как уже было отмечено на предыдущих шагах, процедура обработки исключений определяется ключевым словом catch, вслед за которым в скобках помещена спецификация исключения, а затем в фигурных скобках следует блок обработки исключения. Эта процедура должна быть помещена непосредственно после контролируемого блока. Каждая процедура может обрабатывать только одно исключение заданного или преобразуемого к заданному типа, который указан в спецификации ее параметра. Рассмотрим возможные преобразова ния при отождествлении исключения с процедурой обработки исключений. Стандартная схема:
try { // Произвольный код, порождающий исключения X. } catch (T х) { // Некоторые действия, возможно с х. }
Здесь определена процедура обработки для объекта типа T.
Как уже говорилось, если исключение X есть объект типа T, T&, const T или const T&, то процедура соответствует этому объекту X. Кроме того, соответствие между исключением X и процедурой обработки устанавливается в тех случаях, когда Tи X - одного типа; T -доступный в точке порождения исключения базовый класс для X; T -тип "указатель" и X - типа "указатель", причем X можно преобразовать к типу T путем стандартных преобразований указателя в точке порождения исключения.
Просмотр процедур обработки исключений производится в соответствии с порядком их размещения в программе. Исключение обрабатывается некоторой процедурой в случае, если его тип совпадает или может быть преобразован к типу, обозначенному в спецификации исключения. При этом необходимо обратить внимание, что если один класс (например, ALPHA) является базовым для другого класса (например, BETA), то обработчик исключения BETA должен размещаться раньше обработчика ALPHA. В противном случае обработчик исключения BETA не будет вызван никогда. Рассмотрим такую схему программы:
class ALPHA(); class BETA: public ALPHA {} ; . . . . void f1() { try { ... } catch (BETA) // Правильно. { ... } catch (ALPHA) { ... } . . . . } . . . . void f2() { ... try { ... } catch (ALPHA) // Всегда будет обработан и объект класса { ... // BETA, т.к. "захватываются" исключения ... // классов ALPHA и всех порожденных } // от него. catch (BETA) // Неправильно: заход в обработчик невозможен! { ... } . . . . }
Если из контролируемого блока будет послано исключение типа BETA, то во втором случае, т.е. в f2(), оно всегда будет захвачено обработчиком ALPHA, так как ALPHA является доступным базовым классом для BETA. При этом компилятор Borland C++ выдает предупреждение:
Handler for 'BETA' hidden by previous handler for 'ALPHA' in function f2() (Обработчик 'BETA' "не виден" за размещенным перед ним обработчиком 'ALPHA' В функции f2()).
Заметим, что для явного выхода из процедуры обработки исключения или контролируемого блока можно также использовать оператор goto для передачи управления операторам, находящимся вне этой процедуры или вне контролируемого блока, однако оператором goto нельзя воспользоваться для передачи управления обратно - в процедуру обработки исключений или в контролируемый блок.
После выполнения процедуры обработки программа продолжает выполнение с точки, расположенной после последней процедуры обработки исключений данного контролируемого блока. Другие процедуры обработки исключений для текущего исключения не выполняются.
try { // Тело коитролируемого блока. } catch (спецификация_исключения) { // Тело обработчика исключений. } catch (спецификация_исключения) { // Тело обработчика исключений. } // После выполнения любого обработчика // исполнение программы будет продолжено отсюда.
На следующем шаге мы закончим рассматривать правила обработки исключений.