Программирование >>  Инициализация объектов класса, структура 

1 ... 331 332 333 [ 334 ] 335 336 337 ... 395


class bad alloc : public exception {

...

public:

bad alloc() throw();

bad alloc( const bad alloc s ) throw();

bad alloc s operator=( const bad alloc s ) throw();

virtual ~bad alloc() throw();

virtual const char* what() const throw();

Отметим, что если функция-член объявлена с модификатором const или volatile, как, скажем, what() в примере выше, то спецификация исключений должна идти после него.

Во всех объявлениях одной и той же функции спецификации исключений обязаны содержать одинаковые типы. Если речь идет о функции-члене, определение которой находится вне определения класса, то спецификации исключений в этом определении и в

#include <stdexcept>

<stdexcept> определяет класс overflow error class transport {

...

public:

double cost( double, double ) throw ( overflow error );

...

ошибка: спецификация искчений отучается от той, что задана

в объявлении в списке членов класса

объявлении функции должны совпадать:

double transport::cost( double rate, double distance ) { }

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



class Base { public:

virtual double f1( double ) throw(); 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 ); ...

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

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

d compute( Base *pb ) throw()

try {

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

обработка исключений, возбужденных в Base::f3() catch ( const string S ) { }

catch ( int ) { }

спецификацию исключений функции-члена базового класса:

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

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



int main() {

try {

тело функции main()

catch ( pushCnFull ) { ...

catch ( popCnEmpty ) { ...

блоки называются функциональными. (Mi упоминали их в разделе 11.2.) Например:

Функциональный try-блок ассоциирует группу catch-обработчиков с телом функции. Если инструкция внутри тела возбуждает исключение, то поиск его обработчика ведется среди тех, что следуют за телом функции.

Функциональный try-блок необходим для конструкторов класса. Почему? Определение

имя класса( список параметров ) список инициализации членов:

: член1(важение1 ) , инициазация член1 член2(важение2 ) , инициазация член2 тело функции:

конструктора имеет следующий вид: { /* ... */ }

в1ражение1 и в1ражение2 могут быть выражениями любого вида, в частности функциями, которые возбуждают исключения.

class stackExcp : public Excp { }; class popCbEmpty : public stackExcp { };

class pushCnFull : public stackExcp { };

void stackManip() throw( stackExcp ) {

...

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

19.2.7. Конструкторы и функциональные try-блоки

Можно объявить функцию так, что все ее тело будет заключено в try-блок. Такие try-



1 ... 331 332 333 [ 334 ] 335 336 337 ... 395

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика