D derived;

 try {

  throw derived;

 }

 catch(B b) {

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

 }

 catch(D d) {

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

 }

 return 0;

}

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

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

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

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

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

catch (...) {

 // Обработка всех исключений

}

Здесь заключенное в круглые скобки многоточие обеспечивает совпадение с любым типом данных.

Использование формата catch(...) иллюстрируется в следующей программе.

// В этой программе перехватываются исключения всех типов.

#include

using namespace std;

void Xhandler(int test)

{

 try {

  if(test==0) throw test; // генерирует int-исключение

  if(test==1) throw 'a'; // генерирует char-исключение

  if(test==2) throw 123.23; // генерирует double-исключение

 }

 catch (...) { // перехват всех исключений

  cout << "Перехват!\n";

 }

}

int main()

{

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

 Xhandler (0);

 Xhandler (1);

 Xhandler (2);

 cout << "КОНЕЦ";

 return 0;

}

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

НАЧАЛО

Перехват!

Перехват!

Перехват!

КОНЕЦ

Как видите, все три throw-исключения перехвачены с помощью одной-единственной catch-инетрукции.

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

/* Использование формата catch (...) в качестве варианта "все остальное".

*/

#include

using namespace std;

void Xhandler(int test)

{

 try {

  if(test==0) throw test; // генерирует int-исключение

  if(test==1) throw 'a'; // генерирует char-исключение

  if(test==2) throw 123.23; // генерирует double-исключение

 }

 catch(int i) {

  // перехватывает int-исключение

  cout << "Перехват " << i << '\n';

 }

 catch(...) {

  // перехватывает все остальные исключения

  cout << "Перехват-перехват!\n";

 }

}

int main()

{

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

 Xhandler(0);

 Xhandler(1);

 Xhandler(2);

 cout << "КОНЕЦ";

 return 0;

}

Результаты, сгенерированные при выполнении этой программы, таковы.

НАЧАЛО

Перехват 0

Перехват-перехват!

Перехват-перехват!

КОНЕЦ

Как подтверждает этот пример, использование формата catch(...) в качестве "последнего оплота" catch-последовательности— это удобный способ перехватить все исключения, которые вам не хочется обрабатывать в явном виде. Кроме того, перехватывая абсолютно все исключения, вы предотвращаете возможность аварийного завершения программы, которое может быть вызвано каким-то непредусмотренным (а значит, необработанным) исключением.

Ограничения, налагаемые на тип исключений, генерируемых функциями
Перейти на страницу:

Все книги серии Изучайте C++ с профессионалами

Похожие книги