return(-1);
}
software_design.work_out_marks();
cout << "Average was " << software_design.average_mark()
<< '\n';
return(0);
}
160 Software Design for Engineers and Scientists
Hand execute the program to interpret its use of classes, objects
and polymorphism.
Substitute the char[] buffers in this program with Strings. Test
to break both versions. Are Strings really more error-resilient?
(They certainly should be!)
C has a method for dealing with exceptions: times when some-
thing unexpected happens and special code has to be used for dealing
with it. The basic mechanism is for a function that detects the excep-
tional situation to throw an exception with a statement of the form
throw
exception_type(constructor_parameter_for_exception_type)
This might be used in an expression like
if (invalid_token(x))
throw runtime_error("Invalid x token");
where runtime_error is an exception type dened in the system header
le stdexcept. You can use any type for the exception, but the types
dened in
stdexcept are usually enough. An object of the specied
type gets constructed (in this case with a parameter string
"Invalid x
token"
) and thrown to the nearest catch statement that can deal with it.
To be more precise, when an exception is thrown, the current block or
function is left, as if there were a return statement. All the objects asso-
ciated with the block or function are destroyed and control returns to the
caller, which also immediately returns (destroying all its objects) unless
it is equipped to catch the exception. This goes all the way up the call
tree (i.e. the stack is unwound) until a suitable exception handler is
found. Specication of a suitable exception handler is like this:
try {
// Do many things, one of which causes the exception
...
}
catch (exception_type) {
// Handle exception
...
}
5.7 Exceptions
So any exception of type exception_type thrown in the try block is
caught by the catch block. A catch block can process all exceptions
of any type by being specied with an ellipsis:
catch (...) {
}
and a catch block can rethrow an exception with
throw;
to pass the exception up to a higher level handler if it cant clean
things up alone.
Here is an example of a program that uses the mechanism.
#include <iostream>
using namespace std;
int main() {
int i(0);
char *p[4*1024];
try {
while(i < 4*1024) {
p[i++] = new char[1024*1024];
cout << "Megabyte number " << i <<
" allocated starting at ";
cout << (unsigned int) p[i - 1] << endl;
}
cout << "Successfully allocated 4 Gigabytes\n";
}
catch(bad_alloc) {
cout << "Out of memory after " << i << " Megabytes\n";
}
for (int j = 0; j < i; j++)
delete [] p[j];
return 0;
}
As you see, throw is missing from this program. That is because we
are relying on new to throw a bad_alloc error, which it does when it
cannot allocate any more memory.
You can use this program to nd out how much memory is allocat-
able on your system (up to 4 Gbytes). The amount will depend on how
much virtual disk-based memory the system uses in addition to real
chip memory. On my laptop running Linux, memory runs out at 2931
Mbytes. (Under Windows, compiled with Visual C 98, this pro-
gram reports that all 4 Gbytes are allocated! But closer inspection
reveals that new is returning 0 for the later calls: in other words,
VC is using the old fashioned new which returns 0 when it fails to
allocate and doesnt throw an exception. See page 106.)
In this book we will mostly forego try, throw and catch, and stick
with the return value mechanism for reporting exceptional conditions
and errors. C exception handling allows neat separation of error
handling from other program code, but this is unnecessary in most of
the programs presented here.
Object-oriented programming in C 161

Get Software Design for Engineers and Scientists now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.