A completely different topic: throwing exceptions. When we write
large complicated programs, we might encounter a situation where the
place that an error is detected is not the place where the error
should be handled. One example of this is when an error is detected
inside many nested function calls and we want to handle the error in
the main program. We could exit the program, but that is often
undesirable. We could return an error condition as a return value
from each function, but that is cumbersome. Every time a function is
called, we must check the return value for the error condition. The
alternative is to "throw an exception". To do this we would have a
statement that looks like:
throw(e) ;
Here, e can be an object of any type, but it is customary
to define a class just for the purpose of throwing an exception.
In order for this throw statement to have the intended
behavior, we must have a try-catch block in an "active" function.
Here, an "active" function might be the function that contains
the throw statement, or a function that called the function
that contains the throw statement, or a function that called
that function, etc. That is, the currently active functions are the
main() function and all the functions that have been called,
but have not yet returned. At least one of these functions, must have
a try-catch block that looks like:
try {
// ... some code that eventually calls the function with
// the throw statement
}
catch(Error& e) {
// ... code to handle the error condition
}
The try block can be followed by several catch blocks. Each catch block
must have a different signature. The catch block whose parameter matches
that of the object that is thrown ( e in this case ) is the one
that is invoked. A catch block that has ... as its parameter,
will catch any type of exception.