Exception Handling - Example 16 - Using Standard Exceptions and Deriving Your Own

#pragma warning( disable : 4996 4290)

#include <exception>
#include <stdexcept>
#include <iostream>
#include <cmath>		// for sqrt()
#include <cstring>
#include <cstdlib>
#include <sstream>		// for istreamstream/ostringstream
#include <climits>		// for SHRT_MAX
#include <typeinfo>		// for typeid operator
using namespace std;

// This operator<<() function get used in the catches
ostream& operator<<(ostream& out, const exception& error)
{
	out << "I caught an error of type: " << typeid(error).name() << endl
		<< "Message: " << error.what() << endl;
	return out;
}

class my_domain_error : public domain_error
{
public:
	my_domain_error(const char* message) : domain_error(message)
	{}

	const char* what() const throw ()  // Note: emptry throw required for Dev-C++ (GNU ver 3.4.2)
	{
		static char temp[128];
		strcpy(temp,"my_domain_error: ");
		strcat(temp,domain_error::what());
		return temp;
	}
};

double mysqrt1(double number) throw (domain_error)
{
	if (number < 0) throw domain_error("mysqrt1 error: argument is negative");
	return sqrt(number);
}

double mysqrt2(double number) throw (my_domain_error)
{
	if (number < 0) throw my_domain_error("mysqrt2 error: argument is negative");
	return sqrt(number);
}

// Derive the zero_denominator class from invalid_argument
class zero_denominator : public invalid_argument
{
public:
	zero_denominator() : invalid_argument("Error: zero denominator") {}
};

class fraction
{
	int numerator, denominator;
public:
	fraction(int n = 0, int d = 1) : numerator(n), denominator(d) 
	{
		if (d == 0 ) throw zero_denominator();
	}
};

// convert a hexadecimal string to unsigned int
unsigned hex_string_to_unsigned(string hextext) throw (invalid_argument)
{
	if (hextext.find_first_not_of("0123456789abcdefABCDEF") != string::npos) {
		throw invalid_argument(string("Invalid hexadecimal char in: " ) + hextext);
	}
	istringstream sin(hextext);
	unsigned number;
	sin >> hex >> number;
	return number;
}

// returns sum of two shorts, optional check to make sure sum is valid short
short add2shorts(short one, short two, bool check_limit = false) throw (overflow_error)
{
	if (check_limit) {
		if (static_cast(one) + two > SHRT_MAX) {		// SHRT_MAX is max value of short int (32767)
			ostringstream sout;
			sout << "add2shorts failed with arguments " << one << " and " << two;
			throw overflow_error(sout.str());
		}
	}
	return one + two;
}


int main() 
{
	// test throw/catch of domain_error
	try {
		cout << "mysqrt1(2.0)=" << mysqrt1(2.0) << endl;
		cout << "mysqrt1(-2.0)=" << mysqrt1(-2.0) << endl;
	}
	catch (const domain_error& error) {
		cerr << "Line " << __LINE__ << ": " << error << endl;
	}

	// test throw/catch of logic_error
	try {
		cout << "mysqrt1(-2.0)=" << mysqrt1(-2.0) << endl;
	}
	catch (const logic_error& error) {
		cerr << "Line " << __LINE__ << ": " << error << endl;
	}

	// test throw/catch of (base class) exception
	try {
		cout << "mysqrt1(-2.0)=" << mysqrt1(-2.0) << endl;
	}
	catch (const exception& error) {
		cerr << "Line " << __LINE__ << ": " << error << endl;
	}

	// test throw/catch of my_domain_error
	try {
		cout << "mysqrt2(-2.0)=" << mysqrt2(-2.0) << endl;
	}
	catch (const my_domain_error& error) {
		cerr << "Line " << __LINE__ << ": " << error << endl;
	}

	// test throw/catch of zero_denominator
	try {
		fraction F(2,0);
	}
	catch (const zero_denominator& error) {
		cerr << "Line " << __LINE__ << ": " << error << endl;
	}

	// test throw/catch of invalid_argument
	try {
		cout << "hex abc=" << hex_string_to_unsigned(string("abc")) << endl;
		cout << "hex abz=" << hex_string_to_unsigned(string("abz")) << endl;
	}
	catch (const invalid_argument& error) {
		cerr << "Line " << __LINE__ << ": " << error << endl;
	}

	// test throw/catch of overflow_erro
	try {
		cout << "short 31000+32000=" << add2shorts(31000,32000) << endl;
		cout << "short 31000+32000=" << add2shorts(31000,32000,true) << endl;
	}
	catch (const overflow_error& error) {
		cerr << "Line " << __LINE__ << ": " << error << endl;
	}

	system ("pause");
	return 0;
}

***** Program Output ***** MS Visual C++ 2008
mysqrt1(2.0)=1.41421
Line 102: I caught an error of type: class std::domain_error
Message: mysqrt1 error: argument is negative

Line 110: I caught an error of type: class std::domain_error
Message: mysqrt1 error: argument is negative

Line 118: I caught an error of type: class std::domain_error
Message: mysqrt1 error: argument is negative

Line 126: I caught an error of type: class my_domain_error
Message: my_domain_error: mysqrt2 error: argument is negative

Line 134: I caught an error of type: class zero_denominator
Message: Error: zero denominator

hex abc=2748
Line 143: I caught an error of type: class std::invalid_argument
Message: Invalid hexadecimal char in: abz

short 31000+32000=-2536
Line 152: I caught an error of type: class std::overflow_error
Message: add2shorts failed with arguments 31000 and 32000

***** Program Output ***** gnu g++ version 3.4.2
mysqrt1(2.0)=1.41421
Line 102: I caught an error of type: St12domain_error
Message: mysqrt1 error: argument is negative

Line 110: I caught an error of type: St12domain_error
Message: mysqrt1 error: argument is negative

Line 118: I caught an error of type: St12domain_error
Message: mysqrt1 error: argument is negative

Line 126: I caught an error of type: 15my_domain_error
Message: my_domain_error: mysqrt2 error: argument is negative

Line 134: I caught an error of type: 16zero_denominator
Message: Error: zero denominator

hex abc=2748
Line 143: I caught an error of type: St16invalid_argument
Message: Invalid hexadecimal char in: abz

short 31000+32000=-2536
Line 152: I caught an error of type: St14overflow_error
Message: add2shorts failed with arguments 31000 and 32000