If (coB)
If (coA)
Возбуждение нескольких исключительных ситуаций
Использование исключительных ситуаций
Исключительные ситуации представляются объектами, которые очень похожи на аргументы функции.
Это могут быть объекты любого типа, однако наиболее часто они представляют собой экземпляры класса.
Например, можно объявить класс Overflow, он не нуждается в каком-либо содержимом, необходимо лишь имя:
class Overflow { };
Можно послать экземпляр этого класса для возбуждения исключительной ситуации (предположим, внутри функции):
throw Overflow();
В этом операторе создается объект класса Overflow, который затем посылается обратно в место вызова функции.
Где-нибудь в другом месте программы можно перехватить исключительную ситуацию с помощью оператора catch:
catch (Overflow) {
cout « "Overflow detected!" << endl;
Одно только присутствие объекта Overflow свидетельствует о возбуждении исключительной ситуации.
Объект не обязан предпринимать каких-либо действий (хотя может).
Важно понять, что предыдущий оператор throw посылает объект класса Overflow, который перехватывается оператором catch в другом месте программы.
Может быть, эту концепцию легче будет понять, если снабдить перехватываемый объект именем, используя синтаксис, принятый в объявлениях списков параметров функций:
catch (Overflow overObject){
На этот раз объект в операторе catch получил имя overObject. В других операторах внутри catch можно использовать объект overObject точно так же, как и в операторах, использующих параметр функции.
Например, обычно в классе исключительной ситуации реализуются функции-члены, которые можно вызывать в выражениях внутри catch.
пример:
class Overflow { void Report()
{ cout << "Error: overflow" << endl; }
//В классе Overflow объявляется функция-член //ReportO, отображающая сообщение об //ошибке.
В операторе catch можно вызвать ReportO объекта исключительной ситуации для отображения сообщения об ошибке:
catch (Overflow overObject) {
overObject.Report();// Вызвать //функцию Report брошенного объекта
В функциях можно возбуждать объекты исключительных ситуаций различных типов для поддержки различных условий исключительных ситуаций.
гипотетический пример, в котором обеспечивается поддержка исключительных ситуаций двух видов:
int AnyFun()
{
throw "Big trouble!";
throw Overflow();
return 123;}
Если условие coA справедливо (что бы оно ни значило), функция возбуждает строковую исключительную ситуацию с сообщением "Big trouble!". Если выполняется условие coB, функция посылает объект класса Overflow, создаваемый в данном случае с помощью обращения к конструктору класса по умолчанию. Если же функция не обнаружила ошибок, она возвращается обычным образом, передавая значение 123 тому, кто ее вызвал.
три важных следствия из приведенного примера.
• Функции могут возбуждать одну или несколько исключительных ситуаций различных типов, представляющих различные условия исключительных ситуаций.
• Возбуждение исключительной ситуации немедленно завершает выполнение функции, в которой выполняется оператор throw. »
• Как подсказывают два предыдущих наблюдения, исключительные ситуации обеспечивают альтернативный механизм возврата для функций.
Последнее замечание — ключевое. Функция AnyFunO обычно возвращает целочисленное значение, однако, если возникает исключительная ситуация она возвращает строку или объект класса Overflow.
Только операторы catch могут воспринять эти возвращаемые значения.
Если исключительных ситуаций не возникло, функция завершается нормально, возвращая (необязательно) значение типа, с которым объявляется функция, обратно оператору вызова этой функции.
Можно поддерживать несколько типов объектов исключительных ситуаций с помощью серии операторов catch. Например, для обработки исключительных ситуаций для класса Error и строк м.б. следующие операторы catch один за другим:
catch (Error e) {
// Обработка исключительной ситуации для класса Error } catch (const char* message) {
// Обработка исключительной ситуации для строк }
Введение в блоки try
Для того чтобы принимать объекты исключительных ситуаций некоторой функции, надо вызвать ее внутри блока try:
//Блок try содержит один или несколько //операторов, исключительные ситуации //которых вы хотите перехватывать.
try {
int x = AnyFun();}//вызов ф-ции
// Один или более операторов catch
//должны следовать за блоком try.
catch (Error e) {//если ф-ция
//АнyFun() возбудила искл.ситуацию
e.Report(); //
exit(-1);}
Блок try содержит один или несколько операторов, исключительные ситуации которых вы хотите перехватывать. Один или более операторов catch должны следовать за блоком try.
Это похоже на ситуацию, когда игрок разбегается, чтобы пробить пенальти, а вратарь готовится отразить удар. В любом случае, после блока try следует поместить один или несколько операторов catch, перехватывающих все исключительные ситуации, возбуждаемые этими операторами.
Несколько блоков try и соответствующих им операторов catch могут быть объявлены вложенными, хотя синтаксис в этом случае может привести к запутанному коду.
Например, блок try может иметь вложенные блок try и операторы catch в следующем гипотетическом примере, причем, если в функции FunctionAO возбуждает исключительная ситуация, программа полностью пропускает вложенный блок try:
try {
FunctionA(); //испытать ф-цию во //внешнем //блоке
try {//вложенный блок try //пропускается в случае искл.ситуации
FunctionB();//испытать ф-цию во //внутреннем //блоке
}
catch (Error e) {//перехват //искл.ситуации, возбуждаемой ф=ей //FunctionB();
e.Repor(); // вызвать ф-ю объекта //исключительной ситуации
}
}
catch (Error e) {//перехват //искл.ситуации, возбуждаемой ф=ей //FunctionA();
{ e.Report();} // вызвать ф-ю объекта //исключительной ситуации
Использование блоков try
В блоке try может быть несколько операторов (обычно так и бывает):
try {
cout « "message!" << endl;
int x = AnyFunction();
cout « "x == " « x « endl; }
В блоке try сначала отображается сообщение. Затем в нем вызывается функция AnyFunctionO, результат которой присваивается целочисленной переменной х.
Если в функции AnyFunction возникла исключительная ситуация, блок try немедленно завершается. Другими словами, любое условие исключительной ситуации приводит к пропуску присваивания х и завершающего оператора вывода.
За блоком try должны следовать один или несколько операторов catch (иначе не имеет смысла использовать try). Вот более законченный пример того, как можно обработать несколько исключительных ситуаций, которые может возбудить функция, подобная AnyFunctionO:
try {
cout « "message!" << endl;
int x = AnyFunction();//Если функция за//вершилась нормально, ее результат //присваивается переменной х,
cout « "x == " « x « endl; }
// если функция AnyFunctionO //возбуждает исключительную ситуацию, //выполнение блока try немедленно //прерывается, посланные объекты //перехватываются соответствующими //операторами catch,
catch (char* message) {
cout << "Error! -- " << message « endl;
exit(-1); // Необязательно }
catch (Overflow) {
cout « "Overflow!" « endl;
exit(-2); // Необязательно } // В этом месте программа продолжает выполнение как обычно
В этом более пространном коде сначала испытывается вызов функции AnyFunctionO. Если функция завершилась нормально, ее результат присваивается переменной х, которая отображается в следующем операторе записи в стандартный поток вывода. Если исключительных ситуаций не было, оба оператора catch пропускаются, поскольку нет объектов исключительных ситуаций объявленных типов, которые нужно было бы перехватывать. Конечно, если функция AnyFunctionO возбуждает исключительную ситуацию, выполнение блока try немедленно прерывается, посланные объекты перехватываются соответствующими операторами catch, a именно тем из них, в котором объявлен параметр типа, соответствующего типу данных посланного объекта.
В данном примере в операторах catch вызывается библиотечная функция exitO для аварийного завершения программы. Приведенная реакция не обязательна — вам предоставляется самому решать, что делать в ответ на возбуждение исключительной ситуации.
Вы можете вставить один, два, три или более операторов catch после блока try для обработки исключительных ситуаций различных типов. В этом примере два оператора catch обрабатывают исключительные ситуации для строк и класса Overflow. Любые другие типы исключительных ситуаций, не обрабатываемые операторами catch, передаются вверх по цепочке вызовов. Например, предположим, что функция AnyFunction также возбуждает исключительную ситуацию типа NewException. Если в функции g() был вызван упомянутый выше код, объект этой исключительной ситуации будет передаваться наверх в g(), так как в этом коде обрабатываются только исключительные ситуации типов char* и Overflow.
В конце концов, если ни один оператор catch подходящего типа не был найден в цепочке вызовов, ведущих к исключительной ситуации, выполнение программы прерывается вызовом специального обработчика исполняющей системы. Чтобы этого не произошло, следует запрограммировать все операторы catch для всех возможных типов посылаемых объектов.