Exceptions are special classes that are created and used when an error or exceptions occurs in a program. Normally these are not taught in early CS, becuase the student should focus on good programming style rather than covering their mistakes. These are normally used with large programs that interacted with other systems and have no control over the entire enviroment.
On a certain condition the program may throw
something to signify this situation. Often it is an Exception class. This thrown class searches its current block for a statement to catch it. If it cannot find a catch, it goes up one functional level. If their is no catch there, then it search one higher. This is reapeated until it is caught or program crashes.
The catch
statement is part of a try-catch
block. The try
block contains lines of code that are executed automatically. If something is thrown then it goes to its catch
block. The catch block will have a parameter of the class it is to catch. In the catch
are the lines of code to executed when it catches an exception. There may be more than one catch
block to deal with different exceptions.
Here is an example of a simple try-catch
block.
try{
int num;
cout <<"Enter a number between 1 and 10: ";
cin >>num;
if(num<1 || num>10)
throw "Input should be between 1 and 10."; //throw a string
else
aForeignFunc(num); //possibly this may throw an Exception
}
catch(char* s)
{
cerr <<"Exception given: " <<s;
}
catch(Exception e)
{
cerr <<"Unknown exception caught: " <<e.what(); //returns string
}
The above code demonstrates the basic useage of exceptions. The user enter a number between one and ten. Should the user create an undesired state a string is thrown (as an exception) and it is caught an dealt with. This type of exception if on a simple programming level could be dealth with more robust coding. However the second catch
is more typical of use. The function aForeignFunc()
was not written by the programmer. It may throw an unknown Exception. The programmer compensates this by being prepare to catch an unknown exception.
In order to get more detail about the nature of the exception there are many classes derived off a standard Exception class. Some exmamples of this are a LogicError and RuntimeError derived from expception. LengthError, OutOfRange, InvalidArgument are derived from LogicError. RangeError, OverFlow, and UnderFlow from RuntimeError etc. The heirarchy of such Expcetion are often specified by the individual languages used so consult their documentation on them.
When making your own exceptions it is good programming to nest them in the classes they pertain to and to inherit them from the standard Exception class. They often should just contain information about the nature of the exception created.
To demonstrate personaly designed excpetions let's create some to deal with the IntQueue class with the circular vector. First this is a good case to use exceptions. A stack is a basic class which can be used by other programmers. They do not know the finer details of its implementation and may not change their programms to meet them.
Now what are the exceptions for a stack? There are basically two, underflow--taking a integer off an empty queue--and overflow--adding an integer that wraps over old information. To link these with the stack they will be derived classes from a IntQueue Exception class, which is derived from the basic Expcetion class. Since Exceptions hold basic information on the nature of the class these exception will hold strings describing the error. Now when enqueueing or dequeueing numbers intstead of returning false for bad states an exception is thrown.
class IntQueue
{
//IntQueue implementation
public:
class IntQueueException : public Exception
{
public:
IntQueueException(char* messg) : theMessage(messg) {}
virtual char* what() {return theMessage.c_str();} //from Exception
protected:
string theMessage;
};
class UnderFlow : public IntQueueException //derived from IQE
{
public:
UnderFlow() : theMessage("Attempt to remove integer from empty queue.")
{}
};
class OverFlow : public IntQueueExpcetion //also derived from IQE
{
public:
OverFlow(int i, int sz) : elmnt(i), maxSize(sz), theMessage("Attempted
to add "+i+" to full queue of size "+maxSize+".") {}
protected:
int elmt;
int maxSize;
};
};
void IntQueue::dequeue()
{
if(empty())
throw IntQueueException::UnderFlow();
else
//dequeue
}
void IntQueue::enqueue(int elmnt)
{
if(size()==maxSize())
throw IntQueueException::OverFlow(elmnt, maxSize());
else
//enqueue
}
With these three additional class the IntQueue is now more usable to other programmers. As stated before Expceptions deal with situations out of the programmers hand, not to compensate for programming errors. Now if someone wished to use the IntQueue they can compensate for unknown errors. Here is a block demonstating this.
int main()
{
try
{
IntQueue plates(30);
lunchSimulate(plates, .2);
dispResults(plates);
for(int i=0; i<30; i++)
plates.dequeue();
}
catch(const Exception& e)
{
cerr <<"Some exception: " << e.what();
}
return 0;
}
From the looks this is just a simple simulator program. The very last step is to dequeue all the elements in plates, but what if the programmer assumes that dequeueing from an empty queue does nothing? Quite possibly the queue is not entirely filled and with the current implementation an UnderFlow
might be thrown. However since the queue's exceptions were derived from Exception and the programmer forsaw potention problems, the programm will finish instead of crashing.
Prev -- Back to Portal -- Next