// увы, это не совсем правильно
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() для извещения о том, что индекс вышел за пределы массива. Измените определение этого оператора так, чтобы в подобной ситуации он генерировал исключение. Определите класс, который будет употребляться как тип возбужденного исключения.
11.2. Try-блок
В нашей программе тестируется определенный в предыдущем разделе класс 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;
}