Выбрать главу

#include <iostream>

using namespace std;

// Здесь возможен перехват исключений различных типов.

void Xhandler(int test)

{

 try {

  if(test) throw test;

  else throw "Значение равно нулю.";

 }

 catch (int i) {

 cout << "Перехват! Исключение №: " << i << '\n';

 }

 catch(char *str) {

  cout << "Перехват строки: ";

  cout << str << '\n';

 }

}

int main()

{

 cout << "НАЧАЛО\n";

 Xhandler(1);

 Xhandler(2);

 Xhandler(0);

 Xhandler(3);

 cout << "КОНЕЦ";

 return 0;

}

Эта программа генерирует такие результаты.

НАЧАЛО

Перехват! Исключение №: 1

Перехват! Исключение №: 2

Перехват строки: Значение равно нулю.

Перехват! Исключение №: 3

КОНЕЦ

Как видите, каждая catch-инструкция отвечает только за исключение "своего" типа. В общем случае catch-выражения проверяются в порядке следования, и выполняется только тот catch-блок, в котором тип заданного исключения совпадает с типом сгенерированного исключения. Все остальные catch-блоки игнорируются.

Перехват исключений базового класса

Важно понимать, как выполняются catch-инструкции, связанные с производными классами. Дело в том, что catch-выражение для базового класса "отреагирует совпадением" на исключение любого производного типа (т.е. типа, выведенного из этого базового класса). Следовательно, если нужно перехватывать исключения как базового, так и производного типов, в catch-последовательности catch-инструкцию для производного типа необходимо поместить перед catch-инструкцией для базового типа. В противном случае catch-выражение для базового класса будет перехватывать (помимо "своих") и исключения всех производных классов. Рассмотрим, например, следующую программу:

// Перехват исключений базовых и производных типов.

#include <iostream>

using namespace std;

class В {

};

class D: public В {

};

int main()

{

 D derived;

 try {

  throw derived;

 }

 catch(B b) {

  cout << "Перехват исключения базового класса.\n";

 }

 catch(D d) {

 cout << "Этот перехват никогда не произойдет.\n";

 }

 return 0;

}

Поскольку здесь объект derived — это объект класса D, который выведен из базового класса В, то исключение типа derived будет всегда перехватываться первым catch-выражением; вторая же catch-инструкция при этом никогда не выполнится. Одни компиляторы отреагируют на такое положение вещей предупреждающим сообщением. Другие могут выдать сообщение об ошибке. В любом случае, чтобы исправить ситуацию, достаточно поменять порядок следования этих catch-инструкций на противоположный.

Варианты обработки исключений

Помимо рассмотренных, существуют и другие С++-средства обработки исключений, которые создают определенные удобства для программистов. О них и пойдет речь в этом разделе.

Перехват всех исключений

Иногда имеет смысл создать обработчик для перехвата всех исключений, а не исключений только определенного типа. Для этого достаточно использовать такой формат catch-блока.