Перехват исключений классового типа
Исключение может иметь любой тип, в том числе и тип класса, созданного программистом. В реальных программах большинство исключений имеют именно тип класса, а не встроенный тип. Вероятно, тип класса больше всего подходит для описания ошибки, которая потенциально может возникнуть в программе. Как показано в следующем примере, информация, содержащаяся в объекте класса исключений, позволяет упростить обработку исключений.
Вот один из возможных результатов выполнения этой программы.
После запуска программы пользователю предлагается ввести числитель и знаменатель. Если знаменатель равен нулю, создается объект класса 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; Мы поможем в написании вашей работы! |
Мы поможем в написании ваших работ!