Если исключения организуются в иерархии, то исключение типа некоторого класса может быть перехвачено обработчиком, соответствующим любому его открытому базовому классу. Например, исключение типа pushOnFull перехватывается обработчиками исключений типа stackExcp или Excp.
int main() {
try {
// ...
}
catch ( Excp ) {
// обрабатывает исключения popOnEmpty и pushOnFull
}
catch ( pushOnFull ) {
// обрабатывает исключение pushOnFull
}
Здесь порядок catch-обработчиков желательно изменить. Напоминаем, что они просматриваются в порядке появления после try-блока. Как только будет найден обработчик, способный обработать данное исключение, поиск прекращается. В примере выше Excp может обработать исключения типа pushOnFull, а это значит, что специализированный обработчик таких исключений задействован не будет. Правильная последовательность такова:
catch ( pushOnFull ) {
// обрабатывает исключение pushOnFull
}
catch ( Excp ) {
// обрабатывает другие исключения
}
catch-обработчик для производного класса должен идти первым. Тогда catch-обработчик для базового класса получит управление только в том случае, если более специализированного обработчика не нашлось.
Если исключения организованы в иерархии, то пользователи библиотеки классов могут выбрать в своем приложении уровень детализации при работе с исключениями, возбужденными внутри библиотеки. Например, кодируя функцию main(), мы решили, что исключения типа pushOnFull должны обрабатываться несколько иначе, чем прочие, и потому написали для них специализированный catch-обработчик. Что касается остальных исключений, то они обрабатываются единообразно:
catch ( pushOnFull eObj ) {
// используется функция-член value() класса pushOnFull
// см. раздел 11.3
cerr << "попытка поместить значение " << eObj.value()
<< " в полный стек\n";
}
catch ( Excp ) {
// используется функция-член print() базового класса
Excp::print( "произошло исключение" );