In this video, we'll see how we can create our own exception classes
and throw and catch them.
This has the advantage of making the type of the exception thrown
very explicit and also very specific for our application.
Best practice is to throw objects, not primitive types.
Also we want to throw by value and catch by reference or const reference.
There are several other best practices that we'll talk about in a few videos.
So let's see how we can create our own exception classes.
Here we create two exception classes for our simple example.
The first is a class called divide by 0 exception,
and the second is called negative value exception.
That's it.
Now when we throw an exception in our code, we create an object of one of these types and throw it.
Of course, we can provide constructors, attributes and methods for these classes
as we would for any other class.
And sometimes it's a good idea to provide information about the exception in these attributes,
but as I said, let's keep it simple in this example.
So now let's see what our code would look like throwing these exception objects.
Here's the calculate miles per gallon function that we saw earlier in this section.
The code is pretty much what you would expect.
We check to see if gallons is 0. And if it is,
we throw a divide by 0 exception object by value.
We then check if either miles or gallons are negative.
And if they are, we throw a negative value exception object by value.
That's all there is to. It now let's see how we'll call this function.
Notice that in the try block, we're again calling calculate miles per gallon,
and the function may or may not throw an exception.
If it does not, then we simply assign the result of the function to miles per gallon,
display it, transfer control all the way to the bottom, and display buy,
and we're done.
However, what if calculate miles per gallon does throw an exception.
Remember, it could throw a divide by 0 exception or a negative value exception.
So we create two catch handlers, one for each exception type,
and we write our exception handling code in the catch blocks.
If an exception is thrown then one of these catch handlers will handle it.
Notice how we're catching the exceptions by const ref.
If we had provided attributes or methods in the exception classes, we would access them here.
As before, if we don't handle a particular exception type here,
then c++ will terminate this function and proceed up the call stack
looking for a handler until it finds one or the program terminates.
Let's head over to the IDE, and we'll see this example in action.
All right. So I'm back in the IDE.
And what I've got here is the section 18 workspace,
and I'm in the MPG function exception classes project.
And what we're doing here is we're creating a couple of user-defined exception classes
which we're going to throw and catch, same thing we did in the slides.
You can see here that on lines 5 through 8, we're creating two classes,
one is called divide by 0 exception the other is called negative value exception.
Notice there are no attributes, no methods, no constructors, nothing.
These are just plain old classes, and we're getting the default constructor,and that's good enough for me right now.
We could provide attributes and methods and all kinds of good stuff.
But the names of the classes in this case give us all the information we need about the exception.
So what do we do. Well, we have to throw these exception objects when we
have an error.
So in this case,
we check to see if gallons is equal to 0. And if it is, we throw
a divide by 0 exception object. This causes the default constructor.
We check to see if miles is less than 0 or
gallons is less than 0, right. So if either one of those is negative, then the result won't be valid.
So we're going to throw a negative value exception object.
If none of those is true and we're good to go,
we simply do the calculation and we return miles divided by gallons.
Okay. Just like we've done before. So now down here,
let's look at our try block.
Here we're just grabbing the information from the user,
they've typed in the number of miles the number of gallons. And here's our try block right here.
This is the function we're calling calculate miles per gallon.
It could throw an exception. If it does not throw an exception,
we simply assign two miles per gallon the result of that function call.
We print out the result. We're done.And then we come down here.
And we're finished with the program, and we terminate normally.
If it does throw an exception,
calculate miles per gallon could throw a divide by 0 exception
or a negative value exception.
So I've got two catch handlers here, one for each.
If I get a divide by 0 exception, it's coming in here.
There's my exception object.
If my class did have attributes and methods,
I would certainly be able to call them and use them here.
But in this case, I'm just saying sorry you can't divide by 0.
At that point, I transfer control down to here. It says buy, and I terminate normally.
Same thing with negative value exception. If I get a negative value exception,
I catch that object here. And notice I'm catching both of these by const ref.
Now I display sorry one of your parameters is negative.
The catch handler completes. Again, I come back here and i finish normally.
So I don't have any abnormal termination in this case.
So let's run this. And we'll give it a test real quick.
So let's do a normal test case. 123 miles, and let's say i use 13 gallons.
So my result is 9.46. Exactly what we expect.
Let's run it again.
This time we'll say 123 with 0 gallons. So we expect a divide by 0 message.
Sorry you can't divide by 0. Notice the buy
also happens, which means our function terminates -- our program terminates normally.
Let's run it one more time with negative for miles and
something else for gallons.
Sorry one of your parameters is negative.
And actually we'll do it one more time for the gallons being negative. That's the last test case.
And we'll say negative three.
Sorry one of your parameters is negative. So that's handling all the cases that we've got.
And we're basically creating our own user
defined exception classes.
Now this is pretty common.
And you can see that it's real nice as far as very readable, you're throwing an object
as you're supposed to, you're catching it by const ref like you're supposed to.
In a few videos, we'll talk about c++ standard exception
hierarchy where it's possible for us to
derive our exception classes from one of c++ exception classes.
If you're coming from the world of java and other programming languages,
that's pretty much what you do.
In c++, you have the option of creating these standalone exception classes
or buying into the standard exception class
hierarchy that's provided by c++,
but we'll talk about that soon.