С++ для начинающих


         

Спецификации исключений - часть 2


   virtual int f2( int ) throw( int );

   virtual string f3() throw( int, string );

   // ...

}

class Derived : public Base {

public:

   // ошибка: спецификация исключений накладывает меньше ограничений,

   //         чем на Base::f1()

   double f1( double ) throw( string );

   // правильно: та же спецификация исключений, что и для Base::f2()

   int f2( int ) throw( int );

   // правильно: спецификация исключений f3() накладывает больше ограничений

   string f3( ) throw( int );

   // ...

};

Почему спецификация исключений в производном классе должна накладывать не меньше ограничений, чем в базовом? В этом случае мы можем быть уверены, что вызов виртуальной функции из производного класса по указателю на тип базового не нарушит спецификацию исключений функции-члена базового класса:

// гарантируется, что исключения возбуждены не будут

void compute( Base *pb ) throw()

{

   try {

      pb->f3( );  // может возбудить исключение типа int или string

   }

   // обработка исключений, возбужденных в Base::f3()

   catch ( const string & ) { }

   catch ( int ) { }

}

Объявление f3() в классе Base гарантирует, что эта функция возбуждает лишь исключения типа int или string. Следовательно, функция compute() включает catch-обработчики только для них. Поскольку спецификация исключений f3() в производном классе Derived накладывает больше ограничений, чем в базовом Base, то при программировании в согласии с интерфейсом класса Base наши ожидания не будут обмануты.

В главе 11 мы говорили о том, что между типом возбужденного исключения и типом, заданным в спецификации исключений, не допускаются никакие преобразования. Однако если там указан тип класса, то функция может возбуждать исключения в виде объекта класса, открыто наследующего заданному. Аналогично, если имеется указатель на класс, то функции разрешено возбуждать исключения в виде указателя на объект класса, открыто наследующего заданному. Например:

class stackExcp : public Excp { };

class popObEmpty : public stackExcp { };

class pushOnFull : public stackExcp { };

void stackManip() throw( stackExcp )

{

   // ...

}

Спецификация исключений указывает, что stackManip() может возбуждать исключения не только типа stackExcp, но также popOnEmpty и pushOnFull. Напомним, что класс, открыто наследующий базовому, представляет собой пример отношения ЯВЛЯЕТСЯ, т.е. является

частным случае более общего базового класса. Поскольку popOnEmpty и pushOnFull – частные случаи stackExcp, они не нарушают спецификации исключений функции stackManip().




Содержание  Назад  Вперед