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

1 ... 329 330 331 [ 332 ] 333 334 335 ... 395


int main() {

try {

...

catch ( Excp ) {

/ / обрабатывает искчения popCnEmpty и pushCnFull

catch ( pushCnFull ) {

обрабатывает искчение pushCnFull

Здесь порядок catch-обработчиков желательно изменить. Напоминаем, что они просматриваются в порядке появления после try-блока. Как только будет найден обработчик, способный обработать данное исключение, поиск прекращается. В примере выше Excp может обработать исключения типа pushCnFull, а это значит, что специализированный обработчик таких исключений задействован не будет. Правильная

catch ( pushCnFull ) {

обрабатывает искчение pushCnFull

catch ( Excp ) {

обрабатывает другие искчения

последовательность такова:

catch-обработчик для производного класса должен идти первым. Тогда catch-обработчик для базового класса получит управление только в том случае, если более специализированного обработчика не нашлось.

Если исключения организованы в иерархии, то пользователи библиотеки классов могут выбрать в своем приложении уровень детализации при работе с исключениями, возбужденными внутри библиотеки. Например, кодируя функцию main() , мы решили, что исключения типа pushCnFull должны обрабатываться несколько иначе, чем прочие, и потому написали для них специализированный catch-обработчик. Что касается

catch ( pushCnFull eCbj ) {

используется функция-член value() класса pushCnFull см. раздел 11.3

cerr << попытка поместить значение << eCbj.value() << в полн стек\n ;

catch ( Excp )

споль

Excp::print( произошло искчение );

используется функция-член print() базового

остальных исключений, то они обрабатываются единообразно:

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

класса



void calculate( int parm ) {

try {

mathFunc( parm ); возбуждает искчение divideByZero

catch ( mathExcp mExcp ) астично обрабат г

throw;

/ / частично обрабатывает искчение и генерирует объект-исключение еще раз

mathFunc() возбуждает исключение типа divideByZero?

Будет ли повторно возбужденное исключение иметь тип divideByZero -тот же, что и исключение, возбужденное функцией mathFunc() ? Или тип mathExcp, который указан в объявлении исключения в catch-обработчике?

Напомним, что выражение throw повторно генерирует исходный объект-исключение. Так как исходный объект имеет тип divideByZero, то повторно возбужденное исключение будет такого же типа. В catch-обработчике объект mExcp инициализируется копией подобъекта объекта типа divideByZero, который соответствует его базовому классу MathExcp. Доступ к ней осуществляется только внутри catch-обработчика, она не является исходным объектом-исключением, который повторно генерируется.

Предположим, что классы в нашей иерархии исключений имеют деструкторы:

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

Объявление исключения в catch- обработчике (находящееся в скобках после слова catch) очень похоже на объявление параметра функции. В приведенном примере оно напоминает параметр, передаваемый по значению. Объект eCbj инициализируется копией значения объекта-исключения точно так же, как передаваемый по значению формальный параметр функции инициализируется значением фактического аргумента. Как и в случае с параметрами функции, в объявлении исключения можно использовать ссылки. Тогда catch-обработчик имеет доступ непосредственно к объекту-исключению, созданному выражением throw, а не к его локальной копии. Чтобы избежать копирования больших объектов, параметры типа класса следует объявлять как ссылки; в объявлениях исключений тоже желательно делать исключения типа класса ссылками. В зависимости от того, что находится в таком объявлении (объект или ссылка), поведение обработчика различается (мы покажем эти различия в данном разделе).

В главе 11 были введены выражения повторного возбуждения исключения, которые используются в catch-обработчике для передачи исключения какому-то другому обработчику выше в цепочке вызовов. Такое выражение имеет вид

throw;

Как ведет себя эта инструкция, если она расположена в catch-обработчике исключений базового класса? Например, каким будет тип повторно возбужденного исключения, если



class pushCnFull {

public:

pushCnFull( int i ) : value( i ) { } int value() { return value; }

-pushCnFull(); вновь объявленн деструктор private:

int value;

catch ( pushCnFull eCbj ) {

cerr << попытка поместить значение << eCbj.value() << в полн стек\n ;

Когда они вызываются? Чтобы ответить на этот вопрос, рассмотрим catch-обработчик:

Поскольку в объявлении исключения eCbj объявлен как локальный для catch-обработчика объект, а в классе pushCnFull есть деструктор, то eCbj уничтожается при выходе из обработчика. Когда же вызывается деструктор для объекта-исключения, созданного в момент возбуждения исключения, - при входе в catch-обработчик или при выходе из него? Однако уничтожать исключение в любой из этих точек может быть слишком рано. Можете сказать, почему? Если catch-обработчик возбуждает исключение повторно, передавая его выше по цепочке вызовов, то уничтожать объект-исключение нельзя до момента выхода из последнего catch-обработчика.

19.2.4. Объекты-исключения и виртуальные функции

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

catch ( const Excp seCbj ) {

ошибка: в классе Excp нет функции-члена value() cerr << попытка поместить значение << eCbj.value() << в полн стек\n ;

которая объявлена в классе pushCnFull, нельзя обращаться в catch-обработчике Excp:

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



1 ... 329 330 331 [ 332 ] 333 334 335 ... 395

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