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



 

Исключение может иметь любой тип, в том числе и тип класса, созданного программистом. В реальных программах большинство исключений имеют именно тип класса, а не встроенный тип. Вероятно, тип класса больше всего подходит для описания ошибки, которая потенциально может возникнуть в программе. Как показано в следующем примере, информация, содержащаяся в объекте класса исключений, позволяет упростить обработку исключений.

 

 

Вот один из возможных результатов выполнения этой программы.

 

 

После запуска программы пользователю предлагается ввести числитель и знаменатель. Если знаменатель равен нулю, создается объект класса MyException , который содержит информацию о попытке деления на нуль. Таким образом, класс MyException инкапсулирует информацию об ошибке, которая затем используется обработчиком исключений для уведомления пользователя о случившемся.

Безусловно, реальные классы исключений гораздо сложнее класса MyException . Как правило, создание классов исключений имеет смысл в том случае, если они инкапсулируют информацию, которая бы позволила обработчику исключений эффективно справиться с ошибкой и по возможности восстановить работоспособность программы.

 

Использование нескольких catch‑инструкций

 

Как упоминалось выше, с try ‑блоком можно связывать не одну, а несколько catch ‑инструкций. В действительности именно такая практика и является обычной. Но при этом все catch ‑инструкции должны перехватывать исключения различных типов. Например, в приведенной ниже программе обеспечивается перехват как целых чисел, так и указателей на символы.

 

 

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

 

 

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

 

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

 

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

 

 

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

 

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

 

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

 

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

 

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

 

 

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

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

 

 

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

 

 

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

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

 

 

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

 

 

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

 


Дата добавления: 2018-09-22; просмотров: 333; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!