Hello again! In this video, we are going to look at writing our own exception class. C++ allows you to
do this.
Your class can do anything in theory, but usually the best approach is to derive from one of the existing
standard exception classes, in the exception hierarchy.
So this means we have a consistent interface with the standard exceptions. We can inherit most of the
code we need, instead of watching it again from scratch.
And if your program already has handlers for the base class exception, or the class that you are inheriting
from, then these will automatically handle your exception class as well.
You only need to go through the program and add new handlers if you want to do something different for
your exception.
Deriving from the base class exception is not very useful.
This only has a default constructor, which means that you are not allowed to choose your own error
message.
So what does our class need?
It needs to have constructors which take a string, so we can set the message, and these need to take
both the C++ string and the C-style string.
It needs a copy constructor. And usually we can either inherit that from the parent class, or get the
compiler to synthesize the defaults for us.
We can also override the virtual what() member function from the parent, if we want to add extra functionality
for our class. And we can also add data members, if we want to store information about this particular condition.
And if you do that, it is best to use built-in types.
The exception object is going to be copied into memory off the local stack, so that is why it needs
the copy constructor. The program
may be in an unstable state, so we need to make our object as lightweight as possible.
We should only use the data members that we need, if we need any at all, in fact.
So we should not use any data members, unless we need them, and we should do the minimum amount of work
inside our exception.
And of course, we should be careful not to throw any more exceptions.
As an example, we are going to create an exception test for our student grades program.
We are going to call this invalid_student_grade.
And the idea is if we have a student grade which is less than zero or greater than 100 percent, then
we throw this exception.
This is an error condition where the value is outside the defined range for it.
So the obvious thing to do here is to derive our class from the out_of_range exception class.
This has constructors which take strings, so we need to implement these.
So C-style and C++ strings. We also implements a default constructor, and this will just call the parent
class constructor and pass a suitable error string.
So, "invalid grade:"
"please try again".
The only data we're going to use is the error string, and this is already managed for us by the parent
class, so we do not need any data members of our own. And that means we do not need to do anything special
in the copy constructor, so we can just get the compiler to synthesize one, which will call the parent
class copy constructor.
And likewise, we do not need to define a destructor.
We could also override the virtual what() member function, but we do not need to.
If we were going to, we need to get the signature correct.
So this is a member function, which is const.
It does not change the exception object.
And it is also "noexcept", which we are going to look at a bit later on.
This basically means it is not allowed to throw exceptions, and this should override the parent class version.
And it returns the error string as a C-style string.
So here is our exception class,
bad_student_grade. This inherits from the standard out_of_range exception.
We need to include the standard exception header to get the definition of that.
We have our default, which calls the parent class constructed with a sensible default error message.
Then we have the constructors, which take a string as argument, the C and C++ strings.
We can use the default for the copy and assignment operators, because we do not have any data members,
and we could also override the what() virtual member function.
In our student_grade_class, we have the constructor, which takes the grade as argument. If the grade
is greater than 100,
we create an object by calling the default constructor.
So that is going to set the error message to this default. If it is less than zero,
then we call the constructor with a C string as argument.
So that is going to set the error to be
"bad grade".
And then we have a main() function to try this out.
So we try to create a student_grade object. If the result is invalid,
it should throw an exception which will get caught here, and that will print out the error strings.
So let's try this with a grade, which is greater than 100.
So that calls the default constructor.
And that will give us the default error string.
So there is the call to the default constructor.
If we try it with a negative number,
then this will call the constructor which takes a string, and that will set the error string to "bad
grade".
Okay, so that is it for this video.
I will see you next time, but until then, keep coding!