// увы, это не совсем правильно

throw popOnEmpty;

К сожалению, так нельзя. Исключение – это объект, и функция pop() должна генерировать объект класса соответствующего типа. Выражение в инструкции throw не может быть просто типом. Для создания нужного объекта необходимо вызвать конструктор класса. Инструкция throw для функции pop() будет выглядеть так:

// инструкция является вызовом конструктора

throw popOnEmpty();

Эта инструкция создает объект исключения типа popOnEmpty.

Напомним, что функции-члены pop() и push() были определены как возвращающие значение типа bool: true означало, что операция завершилась успешно, а false – что произошла ошибка. Поскольку теперь для извещения о неудаче pop() и push() используют исключения, возвращать значение необязательно. Поэтому мы будем считать, что эти функции-члены имеют тип void:

class iStack {

public:

// ...

// больше не возвращают значения

void pop( int &value );

void push( int value );

private:

// ...

};

Теперь функции, пользующиеся нашим классом iStack, будут предполагать, что все хорошо, если только не возбуждено исключение; им больше не надо проверять возвращенное значение, чтобы узнать, как завершилась операция. В двух следующих разделах мы покажем, как определить функцию для обработки исключений, а сейчас представим новые реализации функций-членов pop() и push() класса iStack:

#include "stackExcp.h"

void iStack::pop( int ⊤_value )

{

if ( empty() )

throw popOnEmpty();

top_value = _stack[ --_top ];

cout "iStack::pop(): "top_value " endl;

}

void iStack::push( int value )

{

cout "iStack::push( " value " )\n";

if ( full() )

throw pushOnFull( value );

_stack[ _top++ ] = value;

}

Хотя исключения чаще всего представляют собой объекты типа класса, инструкция throw может генерировать объекты любого типа. Например, функция mathFunc() в следующем примере возбуждает исключение в виде объекта-перечисления . Это корректный код C++:

enum EHstate { noErr, zeroOp, negativeOp, severeError };

int mathFunc( int i ) {

if ( i == 0 )

throw zeroOp; // исключение в виде объекта-перечисления

// в противном случае продолжается нормальная обработка

}

Упражнение 11.1

Какие из приведенных инструкций throw ошибочны? Почему? Для правильных инструкций укажите тип возбужденного исключения:

(a) class exceptionType { };

throw exceptionType();

(b) int excpObj;

throw excpObj;

(c) enum mathErr { overflow, underflow, zeroDivide };

throw mathErr zeroDivide();

(d) int *pi = excpObj;

throw pi;

Упражнение 11.2

У класса IntArray, определенного в разделе 2.3, имеется функция-оператор operator[](), в которой используется assert() для извещения о том, что индекс вышел за пределы массива. Измените определение этого оператора так, чтобы в подобной ситуации он генерировал исключение. Определите класс, который будет употребляться как тип возбужденного исключения.

<p>11.2. Try-блок</p>

В нашей программе тестируется определенный в предыдущем разделе класс iStack и его функции-члены pop() и push(). Выполняется 50 итераций цикла for. На каждой итерации в стек помещается значение, кратное 3: 3, 6, 9 и т.д. Если значение кратно 4 (4, 8, 12...), то выводится текущее содержимое стека, а если кратно 10 (10, 20, 30...), то с вершины снимается один элемент, после чего содержимое стека выводится снова. Как нужно изменить функцию main(), чтобы она обрабатывала исключения, возбуждаемые функциями-членами класса iStack?

#include

#include "iStack.h"

int main() {

iStack stack( 32 );

stack.display();

for ( int ix = 1; ix 51; ++ix )

{

if ( ix % 3 == 0 )

stack.push( ix );

if ( ix % 4 == 0 )

stack.display();

if ( ix % 10 == 0 ) {

int dummy;

stack.pop( dummy );

stack.display();

}

}

return 0;

}

Перейти на страницу:

Похожие книги