Sie sind auf Seite 1von 25

#include <iostream> using namespace std; class base { public: virtual void vfunc() { cout << "This is base's

vfunc().\n"; } }; class derived1 : public base { public: void vfunc() { cout << "This is derived1's vfunc().\n"; } }; int main() { base *p, b; derived1 d1; // point to base p = &b; p->vfunc(); // access base's vfunc() // point to derived1 p = &d1; p->vfunc(); // access derived1's vfunc() return 0; } Info PR: 3 I: error Density Diagnosis Links: 4 | 0 SEOquake

Introduction to Exception Handling Foundations of Exceptions Introduction During the execution of a program, the computer will face two types of situation s: those it is prepared to deal with and those it doesnt like. Imagine you write a program that asks the user to supply two numbers to perform a calculation. Her e is such a program: #include <iostream> using namespace std; int main() { double a, b, c; // Request two numbers from the user cout << "Please provide two numbers\n"; cout << "First Number: "; cin >> a; cout << "Second Number: ";

cin >> b; // Multiply the numbers and display the result c = a * b; cout << "\n" << a << " * " << b << " = " << c << "\n\n"; return 0; } This is a classic easy program. When it comes up, the user is asked to simply ty pe two numbers; the program would use them to perform a multiplication and displ ay the result. Imagine that a user, thanks to his infinite creativity or because of just a mist ake, decides to type the name of a country or somebodys telephone number as one o f the requested values. Since a program such as this one is not prepared to mult iply two strings or one number to a string (actually, using operator overloading , you can tell the compiler how to perform almost any type of operation on the v alues of your program), it would not know what to do. The only alternative the c ompiler would have is to send the problem to the operating system, hoping that t he OS would know what to do. What actually happens is that, whenever the compile r is handed a task, it would try to perform the assignment. If it cant perform th e assignment, for any reason it is not prepared for, it would throw an error. As a programmer, if you can anticipate the type of error that could occur in your program, you can catch the error yourself and deal with it by telling the compil er what to do when this type of error occurs. Exceptional Behaviors An exception is a situation that would be unusual for the program that is being processed. As a programmer, you should anticipate any abnormal behavior that cou ld be caused by the user entering wrong information that could otherwise lead to unpredictable results. An error result or an unpredictable behavior on your program not caused by the o perating system but that occurs in your program is called an exception. The abil ity to deal with a programs eventual abnormal behavior is called exception handli ng. C++ provides three keywords to handle an exception. Trying the normal flow: To deal with the expected behavior of a program, use the try keyword as in the following syntax: try {Behavior} The try keyword is required. It lets the compiler know that you are anticipating an abnormal behavior and will try to deal with it. The actual behavior that nee ds to be evaluated is included between an opening curly bracket { and a closing cu rly bracket }. Inside of the brackets, implement the normal flow that the program should follow, at least for this section of the code. Catching Errors: During the flow of the program as part of the try section, if a n abnormal behavior occurs, instead of letting the program crash or instead of l etting the compiler send the error to the operating system, you can transfer the flow of the program to another section that can deal with it. The syntax used b y this section is: catch(Argument) {WhatToDo} This section always follows the try section and there must not be any code betwe en the trys closing bracket and the catch section. The catch keyword is required and follows the try section. The catch behaves a little like a function. It uses an argument that is passed by the previous try section. The argument can be a r egular variable or a class. If there is no argument to pass, the catch must at l

east take a three-period argument as in catch(). The behavior of the catch clause starts with an opening curly bracket { and ends with a closing curly bracket }. The inside of the brackets is called the body of the catch clause. Therefore, use t he body of the catch to deal with the error that was caused. Combined with the try block, the syntax of an exception would be: try { // Try the program flow } catch(Argument) { // Catch the exception } Throwing an error: There are two main ways an abnormal program behavior is trans ferred from the try block to the catch clause. This transfer is actually carried by the throw keyword. Unlike the try and catch blocks, the throw keyword is ind ependent of a formal syntax but still follows some rules.

Facing an Exception An exception is a behavior that should not occur in your program but is likely t o show up. The simplest exception looks like a conditional statement and here is an example: #include <iostream> using namespace std; int main() { int StudentAge; cout << "Student Age: "; cin >> StudentAge; try { if(StudentAge < 0) throw; cout << "\nStudent Age: " << StudentAge << "\n\n"; } catch(...) { } cout << "\n"; return 0; } If you run this program and type a positive integer for the students age, the pro gram would respond by displaying the student age. Thats a good outcome. If you run the program and type a letter or any character, the compiler would di splay the student age as 0. This is the first proof that the compilers are alrea dy configured to deal with some abnormal behavior of a program. When the throw keyword is written by itself, it is a way of asking the compiler to send the exception to another handler. In fact, if there is no other handler written by you, the processing would be handed to the operating system. In this

case, if you run the program and type a negative integer, since the program is n ot prepared to handle the exception itself, because of the presence of a single throw, the operating system would take over and display its own message. This wo uld be abnormal program termination on a Microsoft Windows operating system. #include <iostream> using namespace std; int main() { double Number1, Number2, Result; // Request two numbers from the user cout << "Please provide two numbers\n"; try { cout << "First Number: "; cin >> Number1; cout << "Second Number: "; cin >> Number2; if( Number2 == 0 ) throw; // Perform a division and display the result Result = Number1 / Number2; cout << "\n" << Number1 << " / " << Number2 << " = " << Result < < "\n\n"; } catch(...) { } return 0; } Test the program and supply two valid numbers such as 126.45 and 5.52 Return to your programming environment and test the program again. This time, ty pe 0 for the second number. Predicting Exceptions Writing Local Exceptions Imagine you write a program that requests a students age from the user. As we kno w, everybodys age is positive. Therefore, we need to figure out what to do if the user types a negative number. The expression that checks whether the number ent ered is positive can be written as: if(StudentAge < 0) If the condition is true, the minimum you can do is to send the produced error a way. This is done with the throw keyword: try { if(StudentAge < 0) throw; } Whenever an exception occurs, and whenever you use the try keyword to try an exp ression, you must transfer control to a catch block. This is where you should di splay your own message for the error. Here is an example:

#include <iostream.h> int main() { int StudentAge; try { cout << "Student Age: "; cin >> StudentAge; if(StudentAge < 0) throw "Positive Number Required"; cout << "\nStudent Age: " << StudentAge << "\n\n"; } catch(const char* Message) { cout << "Error: " << Message; } cout << "\n"; return 0; } This program starts with the try block that asks the user to enter a positive nu mber. If the user enters an invalid value, the program examines the throw keywor d. This throw appears to display a string. The compiler registers this string an d since there was an exception, the program exits the try block (it gets out of the try block even if the rest of the try block is fine) and looks for the first catch block it can find. If it finds a catch that doesnt take an argument, it wo uld still use the catch. Otherwise, you can use the catch block to display the e rror string that was sent by the throw keyword. In the example above, the catch uses a string as a pseudo-argument and displays it using a cout extractor. In the example above, the catch block is configured to display a string. Lets con sider the classic division by zero operation. The division by zero is dealt with at different levels. The processor (Intel, AMD, etc) is configured not to allow it. The operating system is also prepared for it. Finally, the compiler has its own interpretation of this operation. Nevertheless, if you suspect it to occur in your program, you can take appropriate measures. When preparing to deal with division by zero, the main idea is to compare the denominator with 0. This compa rison should be performed in a try block. If the comparison renders true, you sh ould avoid the operation and hand the error (exception) to a catch. The catch is usually used to display a message as in the last code. Here is an example: #include <iostream> using namespace std; int main() { double Operand1, Operand2, Result; // Request two numbers from the user cout << "This program allows you to perform a division of two numbers\n" ; cout << "To proceed, enter two numbers: "; try { cout << "First Number: "; cin >> Operand1;

cout << "Second Number: "; cin >> Operand2; // Find out if the denominator is 0 if( Operand2 == 0 ) throw "Division by zero not allowed"; // Perform a division and display the result Result = Operand1 / Operand2; cout << "\n" << Operand1 << " / " << Operand2 << " = " << Result << "\n\n"; } catch(const char* Str) // Catch an exception { // Display a string message accordingly cout << "\nBad Operator: " << Str; } return 0; } The catch clause can use any type of variable as long as you configure it accord ingly. Instead of a string as we have seen, you can send it an integer, then dis play an error depending on the integer that was sent. #include <iostream.h> int main() { double Operand1, Operand2, Result; const char Operator = '/'; // Request two numbers from the user cout << "This program allows you to perform a division of two numbers\n" ; cout << "To proceed, enter two numbers\n"; try { cout << "First Number: "; cin >> Operand1; cout << "Second Number: "; cin >> Operand2; // Find out if the denominator is 0 if( Operand2 == 0 ) throw 0; // Perform a division and display the result Result = Operand1 / Operand2; cout << "\n" << Operand1 << " / " << Operand2 << " = " << Result << "\n\n"; } catch(const int n) // Catch an exception { // Display a string message accordingly cout << "\nBad Operator: Division by " << n << " not allowed\n\n "; }

return 0; } Catching Multiple Exceptions The exceptions as we have seen so far dealt with a single exception in a program . Most of the time, a typical program will throw different types of errors. The C++ language allows you to include different catch blocks. Each catch block can face a specific error. The syntax used is: try { Code to Try } catch(Arg1) { One Exception } catch(Arg2) { Another Exception } The compiler would proceed in a top-down as follows: Following the normal flow control of the program, the compiler enters the try bl ock. If no exception occurs in the try block, the rest of the try block is executed. If an exception occurs in the try block, the try displays a throw that specifies the type of error that happened. The compiler gets out of the try block and examines the first catch If the first catch doesnt match the thrown error, the compiler proceeds with the next catch. This continues until the compiler finds a catch that matches the thr own error. If one of the catches matches the thrown error, its body executes. If no catch m atches the thrown error, you have (or the compiler has) two alternatives. If the re is no catch that matches the error (which means that you didnt provide a match ing catch), the compiler hands the program flow to the operating system (which c alls the terminate() function). Another alternative is to include a catch whose argument is three periods: catch(). The catch() is used if no other catch, provide d there was another, matches the thrown error. The catch(), if included as part o f a catch clause, must always be the last catch, unless it is the only catch of the clause. Multiple catches are written if or when a try block is expected to throw differe nt types of errors. Imagine a program that requests some numbers from the user a nd performs some operation on the numbers. Such a program can be written as foll ows: #include <iostream.h> int main() { double Operand1, Operand2, Result; char Operator; cout << "This program allows you to perform an operation on two numbers\ n"; cout << "To proceed, enter a number, an operator, and a number:\n"; cin >> Operand1 >> Operator >> Operand2; switch(Operator) { case '+':

Result = Operand1 + Operand2; break; case '-': Result = Operand1 - Operand2; break; case '*': Result = Operand1 * Operand2; break; case '/': Result = Operand1 / Operand2; break; default: cout << "Bad Operation"; } cout << "\n" << Operand1 << " " << Operator << " " << Operand2 << " = " << Result; cout << "\n\n"; return 0; } This program works fine as long as the user types a valid sequence of values mad e of a number followed by a valid arithmetic operator, followed by a number. Any thing else, such as an invalid number, an unexpected operator, or a wrong sequen ce (such as Number Number Operator), would produce an unpredictable outcome. Obv iously various bad things could happen when this program is running. To handle the exceptions that this program could produce, you can start with the most likely problem that would occur. Trusting that a user is able to provide t he two numbers that are requested, it is possible that she would type an invalid operator. For example, for this program we will perform only the addition (+), the subtraction(-), the multiplication(*), and the division(/). Therefore, we wi ll first validate the operator. This can be done as follows: #include <iostream> #include <string> using namespace std; int main() { double Operand1, Operand2, Result; char Operator; cout << "This program allows you to perform an operation on two numbers\ n"; try { cout << "To proceed, enter a number, an operator, and a number:\ n"; cin >> Operand1 >> Operator >> Operand2; if(Operator != '+' && Operator != '-' && Operator != '*' && Operator != '/') throw Operator; switch(Operator)

{ case '+': Result = Operand1 + Operand2; break; case '-': Result = Operand1 - Operand2; break; case '*': Result = Operand1 * Operand2; break; case '/': Result = Operand1 / Operand2; break; } cout << "\n" << Operand1 << " " << Operator << " " << Operand2 << " = " << Result; } catch(const char n) { cout << "\nOperation Error: " << n << " is not a valid operator" ; } cout << "\n\n"; return 0; } When this program runs, if the user provides two valid numbers but a wrong opera tor, the program asks a throw to send a character (in fact the character that wa s typed as the operator) that represents the error. Then, when the compiler gets out of the try block, it looks for and finds a catch clause that receives a cha racter value. Therefore, this catch is executed. Imagine that the user wants to perform a division. You need to tell the compiler what to do if the user enters the denominator as 0 (or 0.00). If this happens, the best option, and probably the only one you should consider, is to display a message and get out. To implement this behavior, we will add another catch block that displays a message: #include <iostream.h> int main() { double Operand1, Operand2, Result; char Operator; // Request two numbers from the user cout << "This program allows you to perform a division of two numbers\n" ; cout << "To proceed, enter two numbers\n"; try { cout << "First Number: "; cin >> Operand1; cout << "Operator: "; cin >> Operator;

cout << "Second Number: "; cin >> Operand2; // Make sure the user typed a valid operator if(Operator != '+' && Operator != '-' && Operator != '*' && Operator != '/') throw Operator; // Find out if the denominator is 0 if(Operator == '/') if(Operand2 == 0) throw 0; // Perform an operation based on the user's choice switch(Operator) { case '+': Result = Operand1 + Operand2; break; case '-': Result = Operand1 - Operand2; break; case '*': Result = Operand1 * Operand2; break; case '/': Result = Operand1 / Operand2; break; } // Display the result of the operation cout << "\n" << Operand1 << " " << Operator << " " << Operand2 << " = " << Result << "\n\n"; } catch(const char n) { cout << "\nOperation Error: " << n << " is not a valid operator\ n\n"; } catch(const int p) { cout << "\nBad Operation: Division by " << p << " not allowed\n\ n"; } return 0; } When running this program, if the user types a wrong operator, the compiler cons iders the integer error, gets out f the try block, and looks for a catch that ca n use a character. The first catch can validate it and gets executed. If the user enters the right values (Number Operator Number), then the compiler finds out if the operator entered was a forward slash / used to perform a division . If the user wants to perform a division, the compiler finds out if the second operand, the denominator, is 0. If it is, the program presents a throw that send s an integer. Based on this exception, the compiler gets out of the try block an d starts looking for a catch block that can use an integer. The first catch cant,

it uses a character. Therefore, the compiler looks at the next catch, if any. O ur program provides a second catch that takes an integer as an argument. Therefo re, this catch gets executed. Not all our problems are solved. Image the user types an invalid number. The fir st characteristic of an invalid number is one that contains anything else than a digit (a character between 0 and 9). Since our program performs its operations on decimal numbers, we need to allow the number to have a decimal portion. Inste ad of expecting numeric values from the user, we will request arrays of characte rs. We will use the isdigit() function to examine each character entered in orde r to find out whether any one of them is not a digit. Also, we will allow the us er to type a period that separates the decimal part of a number. If any of the c haracters that the user entered is not a digit, we will throw a string error so a catch can deal with it. This means that we will add a catch that is different from the other already existing ones. So far, we were requesting two double-precision numbers from the user. In order to check each number and validate it, instead of decimals, we will ask the user to type two strings (arrays of characters): #include <iostream> #include <string> using namespace std; int main() { char Number1[40], Number2[40]; double Operand1, Operand2, Result; char Operator; // Request two numbers from the user cout << "This program allows you to perform a division of two numbers\n" ; cout << "To proceed, enter two numbers\n"; try { cout << "First Number: "; cin >> Number1; cout << "Operator: "; cin >> Operator; cout << "Second Number: "; cin >> Number2; // Examine each character of the first operand // to find out if the user included a non-digit in the number for(int i = 0; i < strlen(Number1); i++) if( (!isdigit(Number1[i])) && (Number1[i] != '.') ) // Allow the period throw Number1;// Send the error as a string Operand1 = atof(Number1); // Do the same for the second number entered for(int j = 0; j < strlen(Number2); j++) if( (!isdigit(Number2[j])) && (Number2[j] != '.') ) // Allow the period throw Number2;// Send the error as a string Operand2 = atof(Number2);

// Make sure the user typed a valid operator if(Operator != '+' && Operator != '-' && Operator != '*' && Operator != '/') throw Operator; // Find out if the denominator is 0 if(Operator == '/') if(Operand2 == 0) throw 0; // Perform an operation based on the user's choice switch(Operator) { case '+': Result = Operand1 + Operand2; break; case '-': Result = Operand1 - Operand2; break; case '*': Result = Operand1 * Operand2; break; case '/': Result = Operand1 / Operand2; break; } // Display the result of the operation cout << "\n" << Operand1 << " " << Operator << " " << Operand2 << " = " << Result << "\n\n"; } catch(const int n) { cout << "\nBad Operation: Division by " << n << " not allowed\n\ n"; } catch(const char n) { cout << "\nOperation Error: " << n << " is not a valid operator\ n\n"; } catch(const char *BadOperand) { cout << "\nError: " << BadOperand << " is not a valid number\n\n "; } return 0; } Nesting Exceptions The calculator simulator we have studied so far performs a division as one of it s assignments. We learned that, in order to perform any operation. The compiler must first make sure that the user has entered a valid operator. Provided the op erator is one of those we are expecting, we also asked the compiler to check tha t valid numbers were entered. Even if these two criteria are met, it was possibl e that the user enter 0 for the denominator.

The block that is used to check for a non-zero denominator depends on the except ion that validates the operators. In other words, before we check the value of t he denominator, we have first made sure that a valid number (a string that conta ins only digits and a period) was entered for the denominator. For this reason, the exception that could result from a zero denominator depends on the user firs t entering a valid number for the denominator. C++ allows you to nest exceptions, using the same techniques we applied to nest conditional statements. This means that you can write an exception that depends on, and is subject to, another exception. To nest an exception, write a try bloc k in the body of the parent exception. The nested try block must be followed by its own catch(es). To effectively handle the exception, make sure you include an appropriate throw in the try block. Here is an exception: #include <iostream> #include <string> using namespace std; int main() { char Number1[40], Number2[40]; double Operand1, Operand2, Result; char Operator; cout << "This program allows you to perform an operation on two numbers\ n"; try { cout cout cout cout << << << << "To proceed, enter\n"; "First Number: "; cin >> Number1; "An Operator: "; cin >> Operator; "Second Number: "; cin >> Number2;

// Examine each character of the first operand // to find out if the user included a non-digit in the number for(int i = 0; i < strlen(Number1); i++) if( (!isdigit(Number1[i])) && (Number1[i] != '.') ) // Allow the period throw Number1; // Send the error as a character Operand1 = atof(Number1); // Do the same for the second number entered for(int j = 0; j < strlen(Number2); j++) if( (!isdigit(Number2[j])) && (Number2[j] != '.') ) // Allow the period throw Number2;//[j]; // Send the error as a character Operand2 = atof(Number2); if(Operator != '+' && Operator != '-' && Operator != '*' && Operator != '/') throw Operator; switch(Operator) { case '+': Result = Operand1 + Operand2; cout << "\n" << Operand1 << " + " << Operand2 << " = " << Result;

break; case '-': Result = Operand1 - Operand2; cout << "\n" << Operand1 << " - " << Operand2 << " = " << Result; break; case '*': Result = Operand1 * Operand2; cout << "\n" << Operand1 << " * " << Operand2 << " = " << Result; break; case '/': // The following exception is nested in the previous try try { if(Operand2 == 0) throw "Division by 0 not allowed"; Result = Operand1 / Operand2; cout << "\n" << Operand1 << " / " << Operand2 << " = " << Result; } catch(const char * Str) { cout << "\nBad Operation: " << Str; } break; } } catch(const char n) { cout << "\nOperation Error: " << n << " is not a valid operator" ; } catch(const char *BadOperand) { cout << "\nError: " << BadOperand << " is not a valid number"; } cout << "\n\n"; return 0; } Exceptions and Functions One of the most effective techniques used to deal with code is to isolate assign ments. We have learned this when studying functions. For example, the switch sta tement that was performing the operations in the normal version of our program can be written as follows: #include <iostream> using namespace std; int main() { double Operand1, Operand2, Result; char Operator;

double Calculator(const double N1, const double N2, const char p); cout << "This program allows you to perform a division of two numbers\n" ; cout << "To proceed, enter a number, an operator, and a number:\n"; cin >> Operand1 >> Operator >> Operand2; Result = Calculator(Operand1, Operand2, Operator); cout << "\n" << Operand1 << " " << Operator << " " << Operand2 << " = " << Result; cout << "\n\n"; return 0; } double Calculator(const double Oper1, const double Oper2, const char Symbol) { double Value; switch(Symbol) { case '+': Value = Oper1 + Oper2; break; case '-': Value = Oper1 - Oper2; break; case '*': Value = Oper1 * Oper2; break; case '/': Value = Oper1 / Oper2; break; } return Value; } You can still use regular functions along with functions that handle exceptions. Here is an example: #include <iostream> #include <string> using namespace std; double Calculator(const double N1, const double N2, const char p); int main() { char Number1[40], Number2[40]; double Operand1, Operand2, Result; char Operator; cout << "This program allows you to perform an operation on two numbers\ n";

try { cout cout cout cout << << << << "To proceed, enter\n"; "First Number: "; cin >> Number1; "An Operator: "; cin >> Operator; "Second Number: "; cin >> Number2;

// Examine each character of the first operand // to find out if the user included a non-digit in the number for(int i = 0; i < strlen(Number1); i++) if( (!isdigit(Number1[i])) && (Number1[i] != '.') ) // Allow the period throw Number1; // Send the error as a character Operand1 = atof(Number1); // Do the same for the second number entered for(int j = 0; j < strlen(Number2); j++) if( (!isdigit(Number2[j])) && (Number2[j] != '.') ) // Allow the period throw Number2;//[j]; // Send the error as a character Operand2 = atof(Number2); if(Operator != '+' && Operator != '-' && Operator != '*' && Operator != '/') throw Operator; if(Operator == '/') if(Operand2 == 0) throw 0; Result = Calculator(Operand1, Operand2, Operator); cout << "\n" << Operand1 << " " << Operator << " " << Operand2 << " = " << Result; } catch(const int n) { cout << "\nBad Operation: Division by " << n << " not allowed"; } catch(const char n) { cout << "\nOperation Error: " << n << " is not a valid operator" ; } catch(const char *BadOperand) { cout << "\nError: " << BadOperand << " is not a valid number"; } cout << "\n\n"; return 0; } double Calculator(const double Oper1, const double Oper2, const char Symbol) { double Value; switch(Symbol) {

case '+': Value = Oper1 + Oper2; break; case '-': Value = Oper1 - Oper2; break; case '*': Value = Oper1 * Oper2; break; case '/': Value = Oper1 / Oper2; break; } return Value; } As done in the main() function, any member function of a program can take care o f its own exceptions that would occur in its body. Here is an example of an exce ption handled in a function: #include <iostream> #include <string> using namespace std; int main() { char Number1[40], Number2[40]; double Operand1, Operand2, Result; char Operator; void Calculator(const double N1, const double N2, const char p); cout << "This program allows you to perform an operation on two numbers\ n"; try { cout cout cout cout << << << << "To proceed, enter\n"; "First Number: "; cin >> Number1; "An Operator: "; cin >> Operator; "Second Number: "; cin >> Number2;

// Examine each character of the first operand // to find out if the user included a non-digit in the number for(int i = 0; i < strlen(Number1); i++) if( (!isdigit(Number1[i])) && (Number1[i] != '.') ) // Allow the period throw Number1; // Send the error as a character Operand1 = atof(Number1); // Do the same for the second number entered for(int j = 0; j < strlen(Number2); j++) if( (!isdigit(Number2[j])) && (Number2[j] != '.') ) // Allow the period throw Number2; // Send the error as a character Operand2 = atof(Number2);

if(Operator != '+' && Operator != '-' && Operator != '*' && Operator != '/') throw Operator; Calculator(Operand1, Operand2, Operator); } catch(const char n) { cout << "\nOperation Error: " << n << " is not a valid operator" ; } catch(const char *BadOperand) { cout << "\nError: " << BadOperand << " is not a valid number"; } cout << "\n\n"; return 0; } void Calculator(const double Oper1, const double Oper2, const char Symbol) { double Value; switch(Symbol) { case '+': Value = Oper1 + Oper2; cout << "\n" << Oper1 << " + " << Oper2 << " = " << Value; break; case '-': Value = Oper1 - Oper2; cout << "\n" << Oper1 << " - " << Oper2 << " = " << Value; break; case '*': Value = Oper1 * Oper2; cout << "\n" << Oper1 << " * " << Oper2 << " = " << Value; break; case '/': // The following try exception is nested in the previous try try { if(Oper2 == 0) throw "Division by 0 not allowed"; Value = Oper1 / Oper2; cout << "\n" << Oper1 << " / " << Oper2 << " = " << Value; } catch(const char * Str) { cout << "\nBad Operation: " << Str; } break;

} } Isolating assignments and handing them to functions is a complete and important matter in the area of application programming. Consider a program that handles a simple exception such as this one: #include <iostream> using namespace std; int main() { double Operand1, Operand2, Result; char Operator = '/'; cout << "This program allows you to perform a division of two numbers\n" ; try { cout << "To proceed, enter two numbers: "; cin >> Operand1 >> Operand2; if( Operand2 == 0 ) throw "Division by zero not allowed"; Result = Operand1 / Operand2; cout << "\n" << Operand1 << " / " << Operand2 << " = " << Result ; } catch(const char* Str) { cout << "\nBad Operator: " << Str; } cout << "\n\n"; return 0; } One of the ways you can use functions in exception routines is to have a central function that receives variables, sends them to an external function. The exter nal function tests the value of a variable. If an exception occurs, the external function displays or sends a throw. This throw can be picked up by the function that sent the variable. If the throw carries a value such as an integer or a st ring, the function that originated the try can hand it to a catch or one of its catches to handle the exception. Observe the following example that implements t his scenario: #include <iostream> using namespace std; void Division(const double a, const double b); int main() { double Operand1, Operand2; cout << "This program allows you to perform a division of two numbers\n" ; // Start an exception

try { cout << "To proceed, enter two numbers: "; cin >> Operand1 >> Operand2; // Pass the new values to a function that will analyze them Division(Operand1, Operand2); } catch(const char* Str) { cout << "\nBad Operator: " << Str; } cout << "\n\n"; return 0; } void Division(const double a, const double b) { double Result; // If an exception occurred, if( b == 0 ) // then throw a string to the function caller throw "Division by zero not allowed"; Result = a / b; cout << "\n" << a << " / " << b << " = " << Result; } In this program, the Division function receives two values that it is asked to p erform and division with. The Division function analyzes the second argument tha t represents the denominator. If this argument is zero, an exception is fund and the Division functions throws a string back to the function that sent the argum ents. C++ (as described in the C++ Standards), allows you to specify that a function i s an exception carrier. If you write a function that carries an exception, you c an type the throw keyword followed by parentheses on the right side of the funct ion. Here is an example: #include <iostream> using namespace std; void Division(const double a, const double b) throw(); int main() { double Operand1, Operand2; cout << "This program allows you to perform a division of two numbers\n" ; // Start an exception try { cout << "To proceed, enter two numbers: "; cin >> Operand1 >> Operand2; // Pass the new values to a function that will analyze them Division(Operand1, Operand2); }

catch(const char* Str) { cout << "\nBad Operator: " << Str; } cout << "\n\n"; return 0; } void Division(const double a, const double b) throw() { double Result; // If an exception occurred, if( b == 0 ) // then throw a string to the function caller throw; Result = a / b; cout << "\n" << a << " / " << b << " = " << Result; } As if it were a function, the throw keyword used like this must have parentheses . If it doesnt take any argument, the parentheses must be left empty as in the la st example. If the function that is called from a try block will throw a specifi c type of exception, you can specify this in the parentheses of the throw. Here is an example: #include <iostream> #include <string> using namespace std; void Calculator(const double N1, const double N2, const char p) throw(const char*); int main() { char Number1[40], Number2[40]; double Operand1, Operand2; char Operator; cout << "This program allows you to perform an operation on two numbers\ n"; try { cout cout cout cout << << << << "To proceed, enter\n"; "First Number: "; cin >> Number1; "An Operator: "; cin >> Operator; "Second Number: "; cin >> Number2;

for(int i = 0; i < strlen(Number1); i++) if( (!isdigit(Number1[i])) && (Number1[i] != '.') ) throw Number1; Operand1 = atof(Number1); for(int j = 0; j < strlen(Number2); j++) if( (!isdigit(Number2[j])) && (Number2[j] != '.') ) throw Number2; Operand2 = atof(Number2);

if(Operator != '+' && Operator != '-' && Operator != '*' && Operator != '/') throw Operator; try { Calculator(Operand1, Operand2, Operator); } catch(const char * Str) { cout << "\nBad Operation: " << Str; } } catch(const char n) { cout << "\nOperation Error: " << n << " is not a valid operator" ; } catch(const char *BadOperand) { cout << "\nError: " << BadOperand << " is not a valid number"; } cout << "\n\n"; return 0; } void Calculator(const double Oper1, const double Oper2, const char Symbol) throw(const char*) { double Value; switch(Symbol) { case '+': Value = Oper1 + Oper2; cout << "\n" << Oper1 << " + " << Oper2 << " = " << Value; break; case '-': Value = Oper1 - Oper2; cout << "\n" << Oper1 << " - " << Oper2 << " = " << Value; break; case '*': Value = Oper1 * Oper2; cout << "\n" << Oper1 << " * " << Oper2 << " = " << Value; break; case '/': if(Oper2 == 0) throw "Division by 0 not allowed"; Value = Oper1 / Oper2;

cout << "\n" << Oper1 << " / " << Oper2 << " = " << Value; break; } } A function can also be called to perform more than one test to eventually throw more than one exception. Such a function can (and should) be programmed to throw different types of exceptions. Here is an eample of such a function: double Calculator(const double Oper1, const double Oper2, const char Symbol) { double Value; if(Symbol != '+' && Symbol != '-' && Symbol != '*' && Symbol != '/') throw Symbol; switch(Symbol) { case '+': Value = Oper1 + Oper2; cout << "\n" << Oper1 << " + " << Oper2 << " = " << Value; break; case '-': Value = Oper1 - Oper2; cout << "\n" << Oper1 << " - " << Oper2 << " = " << Value; break; case '*': Value = Oper1 * Oper2; cout << "\n" << Oper1 << " * " << Oper2 << " = " << Value; break; case '/': if(Oper2 == 0) throw "Division by 0 not allowed"; Value = Oper1 / Oper2; cout << "\n" << Oper1 << " / " << Oper2 << " = " << Value; break; } return Value; } As you can see, this function throws two different types of exceptions: a charac ter and a string. When writing such a function that throws, but doesnt handle, di fferent exceptions, you should make sure this function throws different types of exceptions. Here is the reason. When a function throws an exception, it only so metimes specifies the type of exception. It doesnt specify where the exception is going. When the function that called this function receives the thrown type, it must figure out what block must catch the throw. If this function (the function that was called) throws various exceptions of the same type, the calling functi on would send all of them to the same catch. On the other hand, if the called fu

nction throws different types of exceptions, the calling function, when it recei ves the throws, can send each to the appropriate type that would handle it. When a function throws an exception, we learned that we can use the throw keywor d on the right side of the function as if it were a function. We also learned to pass an argument to the throw to specify the type of exception that the called function would deal with. If a function is programmed to throw different types o f exceptions, you can specify this in the arguments of the throw that is appende d to the function. Here are examples: #include <iostream> #include <string> using namespace std; void Calculator(const double N1, const double N2, const char p) throw(const char*, const char); double Validate(const char *N) throw(const char*); int main() { char Number1[40], Number2[40]; double Operand1, Operand2; char Operator; cout << "This program allows you to perform an operation on two numbers\ n"; try { cout cout cout cout << << << << "To proceed, enter\n"; "First Number: "; cin >> Number1; "An Operator: "; cin >> Operator; "Second Number: "; cin >> Number2;

Operand1 = Validate(Number1); Operand2 = Validate(Number2); try { Calculator(Operand1, Operand2, Operator); } catch(const char * Str) { cout << "\nBad Operation: " << Str; } } catch(const char n) { cout << "\nOperation Error: " << n << " is not a valid operator" ; } catch(const char *BadOperand) { cout << "\nError: " << BadOperand << " is not a valid number"; } cout << "\n\n"; return 0; } void Calculator(const double Oper1, const double Oper2, const char Symbol) throw(const char*, const char)

{ double Value; if(Symbol != '+' && Symbol != '-' && Symbol != '*' && Symbol != '/') throw Symbol; switch(Symbol) { case '+': Value = Oper1 + Oper2; cout << "\n" << Oper1 << " + " << Oper2 << " = " << Value; break; case '-': Value = Oper1 - Oper2; cout << "\n" << Oper1 << " - " << Oper2 << " = " << Value; break; case '*': Value = Oper1 * Oper2; cout << "\n" << Oper1 << " * " << Oper2 << " = " << Value; break; case '/': if(Oper2 == 0) throw "Division by 0 not allowed"; Value = Oper1 / Oper2; cout << "\n" << Oper1 << " / " << Oper2 << " = " << Value; break; } } double Validate(const char* N) throw(const char*) { double Valid; for(int i = 0; i < strlen(N); i++) if( (!isdigit(N[i])) && (N[i] != '.') ) throw N; Valid = atof(N); return Valid; }

Previous

Copyright 2000-2010 FunctionX, Inc.

Next

Das könnte Ihnen auch gefallen