Стандартная библиотека классов С++ содержит девять классов исключений, разделенных на две основные группы (группа динамических ошибок и группа логических ошибок), которые приведены в табл. 7.3. Группа динамических ошибок представляет ошибки, которые трудно предотвратить. В группу логических ошибок входят ошибки, которые «теоретически предотвратимы».
Таблица7.3. Классы ди н амических и логических ошибок |
Классы динамических ошибок |
Классы логических ошибок |
range_error |
domain_error |
underflow_error |
invalid_argument |
overflow_error |
length_error |
|
out_of_range |
На рис. 7.4 показана схема отношений между классами для семейства классов runtime_error. Это семейство выведено из класса exception. Из класса runtime_error выведено три класса: range_error, overflow_error Hunderflow_error, которые сооб щ ают об ошибках промежуточных вычислений (об ошибках выхода за границы диапазона, переполнения и потери значимости). Потомки класса runtime_error наслелуют основное поведение от своего предка, класса exception (имеется в виду метод what (), оператор присваивания operator= () и конструкторы класса обработки исключений).
Рис. 7.4. Схема отношений между классами для семейства классов runtime_error |
Каждый класс обеспечивает определен н ый диапазон наслелуемых функций, которыми программист может воспользоваться для конкретной программы. Например, классы defect_responseи exception_response,созданные в листингах 7.1 и 7.2, можно вывести как из класса runtime_error,так и из класса logic_error.Но сначала полезно рассмотреть работу базовых классов исключений без специализации. В листинге 7.3 показано, как можно сгенерировать объекты классов exceptionи logic__error.
// Листинг 7.3. Генерирование объекта класса exception и
// объекта класса logic_error
try{
exception X; throw(X) ;
} catch(const exception &X) {
cout « X.what() << endl;
}
try{
logic_error Logic(«JIorn4ecKaH ошибка»); throw(Logic);
} catch(const exception &X) {
cout << X.what() « endl;
}
Объекты базового класса exception обладают лишь конструкторами, деструкторами, средствами присваивания, копирования и простейшего вывода отчетной информации. При сбое они не способны его скорректировать. Здесь можно рассчитывать лишь на вывод сообщения об ошибке, возвращаемого методом what() классов исключений. Это сообщение будет определяться строкой, переданной конструктору для объекта класса logic_error. В листинге7.3 переданная конструктору строка «Логическая ошибка» будет возвращена методом what() в catch-блoкe и выведена в виде сообщения.
Семейство классов logic_error выведено из класса exception. И в самом деле, большинство функций классов этого семейства также унаследовано от класса exception. Класс exception содержит метод what() , используемый для уведомления пользователя о возникшей ошибочной ситуации. Каждый класс logic_error-семейства содержит конструктор, используемый для привязки сообщения, специфического для данного конкретного класса. Схема отношений между классами для семейства logic_error показана на рис. 7.5.
Рис. 7.5. Схема отношений между классами для семейства классов logic_error |
Подобно классам семейства runtime_error эти классы также предназначены для последующей специализации. Если пользователь не расширит их функциональность, они не смогут сделать ничего, кроме как уведомить об ошибке и ее типе. Упомянутые выше девять классов исключений общего назначения не обеспечивают никаких действий по корректировке ситуации или обработке ошибок.
Выведение новых классов исключений
Классы исключений можно использовать как есть, т.е. просто для вывода сообщений с описанием происшедших ошибок. Но в качестве метода обработки исключений такой подход практически бесполезен. Просто знать о возникновении исключительной ситуации — не слишком большой шаг на пути повышения надежности ПО. Реальная польза иерархии классов исключений состоит в обеспечении ими архитектурной карты дорог для проектировщика и разработчика. Классы исключений предусматривают основные типы ошибок, которые разработчик может уточнить. Многие исключительные ситуации, которые возникают в среде выполнения, можно было бы отнести к категориям, «охватываемым» семействами классов logic_errorили runtime_error.В качестве примера возьмем класс runtime_errorи продемонстрируем, как можно «сузить» его специализацию. Класс runtime_errorявляется потомком класса exception.Специализацию класса можно определить с помощью механизма наследования. Вот пример:
Читать дальше