Классы исключений exception
, bad_cast
и bad_alloc
определяют также стандартный конструктор. Классы runtime_error
и logic_error
не имеют стандартного конструктора, но имеют конструкторы, получающие символьную строку в стиле С или аргумент библиотечного типа string
. Эти аргументы предназначены для дополнительной информации об ошибке. Функция what()
этих классов возвращает сообщение, использованное для инициализации объекта исключения. Поскольку функция what()
виртуальная, при обработке ссылки на базовый тип вызов функции what()
выполнит ту версию, которая соответствует динамическому типу объекта исключения.
В приложениях иерархию исключений зачастую дополняют, определяя классы, производные от класса exception
(или другого библиотечного класса, производного от него). Такие классы представляют исключения, специфические для данного приложения.
Если бы предстояло создать реальное приложение книжного магазина, его классы были бы гораздо сложнее, чем в примерах этой книги. Одной из причин усложнения является обработка исключений. Фактически пришлось бы создать собственную иерархию исключений, отражающую вероятные проблемы, специфические для данного приложения. В этом проекте могли бы понадобиться следующие классы:
//
class out_of_stock: public std::runtime_error {
public:
explicit out_of_stock(const std::string &s):
std::runtime_error(s) { }
};
class isbn_mismatch: public std::logic_error {
public:
explicit isbn_mismatch(const std::string &s):
std::logic_error(s) { }
isbn_mismatch(const std::string &s,
const std::string &lhs, const std::string &rhs):
std::logic_error(s), left(lhs), right(rhs) { }
const std::string left, right;
};
Здесь специфические для приложения классы исключения определены как производные от стандартного класса исключения. Любую иерархию классов, включая иерархию исключений, можно рассматривать как слоистую структуру. По мере углубления иерархии каждый слой становится более специализированным. Например, первым и наиболее общим слоем иерархии является класс exception
. При получении объекта этого типа будет известно только то, что в приложении произошла какая-то ошибка.
Второй слой специализирует исключение на две обширные категории: ошибки времени выполнения и логические ошибки. Ошибки времени выполнения могут быть обнаружены только при запуске программы. Логические ошибки, в принципе, могут быть обнаружены в приложении.
Классы исключений книжного магазина представляют даже более специализированный слой. Класс out_of_stock
представляет проблему времени выполнения, специфическую для данного приложения. Он используется для оповещения о нарушении порядка выполнения. Класс исключения isbn_mismatch
представляет собой более специализированную форму класса logic_error
. В принципе программа может обнаружить несоответствие ISBN, вызвав функцию isbn()
.
Собственные классы исключений применяются точно так же, как и классы стандартной библиотеки. Одна часть программы передает объект одного из этих классов, а другая получает и обрабатывает его, устраняя проблему. Например, для перегруженного оператора суммы класса Sales_item
можно создать класс исключения isbn_mismatch
, передаваемого в случае обнаружения ошибки несовпадения ISBN.
//
Sales_data&
Sales_data::operator+=(const Sales_data& rhs) {
if (isbn() != rhs.isbn())
throw isbn_mismatch("wrong isbns", isbn(), rhs.isbn());
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
Обнаружив эту ошибку, использующий оператор +=
код сможет передать соответствующее сообщение об ошибке и продолжить работу.
//
Sales_data item1, item2, sum;
while (cin >> item1 >> item2) { //
try {
sum = item1 + item2; //
// использовать сумму