Activity 17-2 - Defining Your Own Exception Classes
                          Multiple Exceptions



A throw_statement can throw a value of any type.  A common thing to do is to define a class whose objects can carry the precise kind of information you want to throw to the catch-block.  For what other reason may you want to have a specialized exception class?  You can have different types to identify each possible kind of exceptional situation.  Remember that an exception class is just a class.  What makes it an exception class is how it's used.

Here is a revised version of the program in the previous activity with a home-made exception class.

// P17_2.cpp - This program computes donuts per glasses of milk
// It uses a home-made exception class
#include <iostream>
using namespace std;

class NoMilk
{
public:
    NoMilk();
    NoMilk(int how_many);
    int get_donuts();
private:
    int count;
};

int main()
{
    int donuts, milk;
    double dpg;

    try
    {
        cout << "Enter number of donuts:\n";
        cin >> donuts;
        cout << "Enter number of glasses of milk:\n";
        cin >> milk;

        if (milk <= 0)
               throw NoMilk(donuts);

        dpg = donuts/double(milk);
        cout << donuts << " donuts.\n"
             << milk << " glasses of milk.\n"
             << "You have " << dpg
             << " donuts for each glass of milk.\n";
    }
    catch(NoMilk e)
    {
        cout << e.get_donuts() << " donuts, and No Milk!\n"
             << "Go buy some milk.\n";
    }
    cout << "End of program.";
    return 0;
}
 

NoMilk::NoMilk()
{}
NoMilk::NoMilk(int how_many) : count(how_many)
{}

int NoMilk::get_donuts()
{
    return count;
}

In the above program we had:

throw NoMilk(donuts);

The part NoMilk(donuts) is an invocation of a constructor for the class NoMilk.  This constructor takes one int argument and creates an object of the class NoMilk.  That object is then "thrown."

Important Note: When catching multiple exceptions, the order of the catch-blocks can be important.  You have to remember that the catch-block will be tried in the order that they appear in the program, thus, the first one that matches the type of the exception thrown is the one that is executed.

Interesting case: The following is a special kind of catch-block that will catch a thrown value of any type:
catch (...) // The three dots must be placed
{
    <place whatever you want in here>
}

This is the most general case, so this catch should be included at the end after all other cases.
 

Exercise 17.2
The following program solves a quadratic equation.  Use an exception handler similar to the one above to handle the exceptional situation that has occured.
Include a general exception handler for exceptions that may need to be included, such as for the case that all coefficients are 0 or for other situations.

// Program to solve quadratic equation
#include <iostream>
#include <cstdlib>
#include <cmath>

using namespace std;

int main( )
{
    double a, b, c; // coefficient of ax^2 + bx + c = 0
    double x1, x2; // The two roots

    double temp;

    cout << "Enter the three coefficients \n";
    cin >> a >> b >> c;

    if(a != 0)
    {
            temp = b*b - 4*a*c;
            if(temp >= 0)
            {
                    // Two roots
                    x1 = ( -b + sqrt(temp))/2*a;
                    x2 = ( -b - sqrt(temp))/2*a;
                    cout << "The two roots are: " << x1 << " and " << x2 << endl;
            }
            else
            {
                    cout << "Square root of negative values is not defined \n";
                    exit(1);
            }

    }
    else
    {
            cout << "Division by zero, not defined \n";
            exit(1);
    }

    return 0;

}