WEBVTT

00:00.180 --> 00:07.710
Hello again! In this video, we are going to look at writing our own exception class. C++ allows you to

00:07.710 --> 00:08.190
do this.

00:08.550 --> 00:14.340
Your class can do anything in theory, but usually the best approach is to derive from one of the existing

00:14.610 --> 00:18.180
standard exception classes, in the exception hierarchy.

00:18.840 --> 00:24.240
So this means we have a consistent interface with the standard exceptions. We can inherit most of the

00:24.240 --> 00:26.550
code we need, instead of watching it again from scratch.

00:27.420 --> 00:32.880
And if your program already has handlers for the base class exception, or the class that you are inheriting

00:32.880 --> 00:36.990
from, then these will automatically handle your exception class as well.

00:37.650 --> 00:42.930
You only need to go through the program and add new handlers if you want to do something different for

00:42.930 --> 00:43.650
your exception.

00:46.710 --> 00:49.890
Deriving from the base class exception is not very useful.

00:50.310 --> 00:55.790
This only has a default constructor, which means that you are not allowed to choose your own error

00:55.800 --> 00:56.220
message.

01:01.780 --> 01:03.160
So what does our class need?

01:03.580 --> 01:09.790
It needs to have constructors which take a string, so we can set the message, and these need to take

01:09.790 --> 01:13.630
both the C++ string and the C-style string.

01:14.770 --> 01:20.470
It needs a copy constructor. And usually we can either inherit that from the parent class, or get the

01:20.470 --> 01:23.440
compiler to synthesize the defaults for us.

01:24.370 --> 01:31.600
We can also override the virtual what() member function from the parent, if we want to add extra functionality

01:31.600 --> 01:38.620
for our class. And we can also add data members, if we want to store information about this particular condition.

01:39.190 --> 01:41.890
And if you do that, it is best to use built-in types.

01:45.520 --> 01:50.650
The exception object is going to be copied into memory off the local stack, so that is why it needs

01:50.650 --> 01:53.080
the copy constructor. The program

01:53.080 --> 01:58.720
may be in an unstable state, so we need to make our object as lightweight as possible.

02:00.040 --> 02:04.630
We should only use the data members that we need, if we need any at all, in fact.

02:05.290 --> 02:10.810
So we should not use any data members, unless we need them, and we should do the minimum amount of work

02:11.080 --> 02:12.400
inside our exception.

02:12.880 --> 02:15.850
And of course, we should be careful not to throw any more exceptions.

02:20.690 --> 02:25.400
As an example, we are going to create an exception test for our student grades program.

02:25.940 --> 02:28.280
We are going to call this invalid_student_grade.

02:29.060 --> 02:34.940
And the idea is if we have a student grade which is less than zero or greater than 100 percent, then

02:34.940 --> 02:35.960
we throw this exception.

02:36.680 --> 02:41.300
This is an error condition where the value is outside the defined range for it.

02:41.870 --> 02:47.600
So the obvious thing to do here is to derive our class from the out_of_range exception class.

02:49.310 --> 02:53.180
This has constructors which take strings, so we need to implement these.

02:53.730 --> 03:01.010
So C-style and C++ strings. We also implements a default constructor, and this will just call the parent

03:01.010 --> 03:04.450
class constructor and pass a suitable error string.

03:04.460 --> 03:06.020
So, "invalid grade:"

03:06.110 --> 03:06.920
"please try again".

03:09.610 --> 03:15.220
The only data we're going to use is the error string, and this is already managed for us by the parent

03:15.220 --> 03:21.310
class, so we do not need any data members of our own. And that means we do not need to do anything special

03:21.310 --> 03:25.900
in the copy constructor, so we can just get the compiler to synthesize one, which will call the parent

03:25.900 --> 03:27.100
class copy constructor.

03:28.380 --> 03:31.590
And likewise, we do not need to define a destructor.

03:34.750 --> 03:38.950
We could also override the virtual what() member function, but we do not need to.

03:39.580 --> 03:42.550
If we were going to, we need to get the signature correct.

03:43.000 --> 03:44.920
So this is a member function, which is const.

03:45.640 --> 03:47.380
It does not change the exception object.

03:48.100 --> 03:51.160
And it is also "noexcept", which we are going to look at a bit later on.

03:51.640 --> 03:57.790
This basically means it is not allowed to throw exceptions, and this should override the parent class version.

03:58.390 --> 04:01.150
And it returns the error string as a C-style string.

04:02.710 --> 04:04.690
So here is our exception class,

04:04.690 --> 04:09.220
bad_student_grade. This inherits from the standard out_of_range exception.

04:09.760 --> 04:13.750
We need to include the standard exception header to get the definition of that.

04:14.760 --> 04:20.790
We have our default, which calls the parent class constructed with a sensible default error message.

04:21.660 --> 04:27.000
Then we have the constructors, which take a string as argument, the C and C++ strings.

04:28.230 --> 04:33.240
We can use the default for the copy and assignment operators, because we do not have any data members,

04:34.020 --> 04:37.440
and we could also override the what() virtual member function.

04:40.770 --> 04:46.950
In our student_grade_class, we have the constructor, which takes the grade as argument. If the grade

04:46.960 --> 04:48.180
is greater than 100,

04:48.210 --> 04:51.540
we create an object by calling the default constructor.

04:52.470 --> 04:57.150
So that is going to set the error message to this default. If it is less than zero,

04:57.570 --> 05:01.350
then we call the constructor with a C string as argument.

05:01.650 --> 05:03.990
So that is going to set the error to be

05:04.320 --> 05:04.950
"bad grade".

05:07.620 --> 05:09.720
And then we have a main() function to try this out.

05:10.260 --> 05:14.640
So we try to create a student_grade object. If the result is invalid,

05:15.000 --> 05:19.170
it should throw an exception which will get caught here, and that will print out the error strings.

05:20.190 --> 05:24.180
So let's try this with a grade, which is greater than 100.

05:26.010 --> 05:28.140
So that calls the default constructor.

05:28.500 --> 05:30.420
And that will give us the default error string.

05:32.130 --> 05:34.500
So there is the call to the default constructor.

05:37.130 --> 05:38.870
If we try it with a negative number,

05:41.640 --> 05:46.770
then this will call the constructor which takes a string, and that will set the error string to "bad

05:46.770 --> 05:47.130
grade".

05:48.090 --> 05:49.470
Okay, so that is it for this video.

05:49.980 --> 05:53.130
I will see you next time, but until then, keep coding!
