Правила программирования на С и С++. Главы 7-8 - По возможности возбуждайте объекты типа error

ОГЛАВЛЕНИЕ

160. По возможности возбуждайте объекты типа error.

Листинг 15 показывает простую систему определений класса для возбуждения исключений. Я могу перехватить ошибки чтения или записи подобным образом:

try

{

file f("name", "rw");

buffer b;

b = f.read() f.write( b );

}

catch( file::open_error ?r )

{

// Файл не существует или не может быть открыт.}

catch( file::io_error ?r )

{

// Какая-то из неисправимых ошибок ввода/вывода.}Если меня волнует лишь то, что произошла ошибка определенного вида, и не волнует, какого конкретно, то я могу сделать так: file f;

try

{

buffer b;

b = f.read()

f.write( b );

}

catch( file::error ?r )

{

// ...}Листинг 15. Классы исключений
  1. class file
  2. {
  3. public:
  4. class error {};
  5. class open_error : public error {};
  6. class io_error : public error {};
  7. // ...
  8. }
Этот код работает, потому что объект file::read_error является объектом типа file::error (так как относится к производному классу). Вы всегда можете перехватить объект производного класса, используя ссылку или указатель базового класса.

Я мог бы также предложить другой класс, использующий тот же самый механизм:

class long_double

{

public:

class error {};

class didvide_by_zero : public error {};

// ...

};Так как классы error являются вложенными определениями, то именами на самом деле являются file::error и long_double::error, поэтому здесь нет конфликта имен.

Для упрощения сопровождения я всегда использую error в качестве своего базового класса для исключений. (Я не мог использовать производный класс, даже если здесь был бы возможен всего один вид ошибки). Таким образом, я знаю, что имея возбуждающий исключение класс some_class, можно перехватить это исключение при помощи:

catch(some_class::error ?r)Эту ошибку искать не придется. Если применяется наследование, то я использую базовый класс error таким образом: class employee

{

public:

class error {};

class database_access_error : public error {};

};

class peon : public employee

{

class error : public employee::error {};

class aagh : public error {};

};Этим способом исключение aagh может быть перехвачено как peon::aagh, peon::error или employee::error.

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