Your code contains a lot of misconceptions. The short answer is yes, you can change what()
in order to return whatever you want. But let's go step by step.
#include <iostream>
#include <exception>
#include <stdexcept>
#include <sstream>
using namespace std;
class DivideByZeroException: public runtime_error {
public:
DivideByZeroException(int x, int y)
: runtime_error( "division by zero" ), numerator( x ), denominator( y )
{}
virtual const char* what() const throw()
{
cnvt.str( "" );
cnvt << runtime_error::what() << ": " << getNumerator()
<< " / " << getDenominator();
return cnvt.str().c_str();
}
int getNumerator() const
{ return numerator; }
int getDenominator() const
{ return denominator; }
template<typename T>
static T divide(const T& n1, const T& n2)
{
if ( n2 == T( 0 ) ) {
throw DivideByZeroException( n1, n2 );
}
return ( n1 / n2 );
}
private:
int numerator;
int denominator;
static ostringstream cnvt;
};
ostringstream DivideByZeroException::cnvt;
In the first place, runtime_error
, derived from exception
, is the adviced exception class to derive from. This is declared in the stdexcept header. You only have to initialize its constructor with the message you are going to return in the what()
method.
Secondly, you should appropriately name your classes. I understand this is just a test, but a descriptive name will always help to read and understand your code.
As you can see, I've changed the constructor in order to accept the numbers to divide that provoked the exception. You did the test in the exception... well, I've respected this, but as a static function which can be invoked from the outside.
And finally, the what()
method. Since we are dividing two numbers, it would be nice to show that two numbers that provoked the exception. The only way to achieve that is the use of ostringstream. Here we make it static so there is no problem of returning a pointer to a stack object (i.e., having cnvt
a local variable would introduce undefined behaviour).
The rest of the program is more or less as you listed it in your question:
int main()
{
int a, b, result;
cout << endl;
cout << "Enter a number to be divided " << endl;
cout << endl;
cin >> a;
cout << endl;
cout << "You entered " << a << " , Now give me a number to divide by " << endl;
cin >> b;
try
{
result = DivideByZeroException::divide( a, b );
cout << "
The two numbers divided are " << result << endl;
}
catch(const DivideByZeroException &e)
{
cout << e.what() << endl;
}
return 0;
}
As you can see, I've removed your return main()
instruction. It does not make sense, since you cannot call main()
recursively. Also, the objective of that is a mistake: you'd expect to retry the operation that provoked the exception, but this is not possible, since exceptions are not reentrant. You can, however, change the source code a little bit, to achieve the same effect:
int main()
{
int a, b, result;
bool error;
do {
error = false;
cout << endl;
cout << "Enter a number to be divided " << endl;
cout << endl;
cin >> a;
cout << endl;
cout << "You entered " << a << " , Now give me a number to divide by " << endl;
cin >> b;
try
{
result = DivideByZeroException::divide( a, b ); // trys my exception from my class to see if there is an issue
cout << "
The two numbers divided are " << result << endl;
}
catch(const DivideByZeroException &e) // if the error is true, then this calls up the eror message and restarts the progrm from the start.
{
cout << e.what() << endl;
error = true;
}
} while( error );
return 0;
}
As you can see, in case of an error the execution follows until a "proper" division is entered.
Hope this helps.