WEBVTT

00:00.300 --> 00:05.790
Hello again! In this video, we are going to look at conversion operators. A conversion operator

00:05.790 --> 00:10.260
is a member function that converts an object of the class into some other type.

00:10.590 --> 00:15.360
So, in a way, it is like being able to define your own casts for your classes.

00:16.950 --> 00:19.140
A class can define a conversion operator.

00:19.560 --> 00:24.000
It is a member function, which converts an object of the class to some other type.

00:24.360 --> 00:32.160
It can be any other type we want, and we can do the conversion however we want to. With our Test class,

00:32.490 --> 00:36.960
we can define a conversion operator to int. The name of this function

00:36.960 --> 00:39.720
will be operator int. It takes no arguments.

00:40.290 --> 00:43.350
We make it const because we do not want to modify the object.

00:43.680 --> 00:45.970
We are just returning its value in a different form.

00:45.990 --> 00:46.410
That is all.

00:47.070 --> 00:52.230
And then inside the body of the function, we return some value of this type.

00:52.680 --> 00:56.230
In this case, we are just going to return the int member.

00:57.540 --> 01:03.660
And then, whenever we use an object of this class where an int is expected or could be used, then the

01:03.660 --> 01:06.270
compiler will add a call to this conversion operator.

01:08.250 --> 01:13.530
For example, if we have something like this. We have an object of our class and we add 5 to it.

01:14.340 --> 01:17.880
The compiler will have to find a function that can resolve this call.

01:18.300 --> 01:20.250
So it is obviously going to be some sort of addition

01:20.250 --> 01:27.030
operator. The compiler does not know about any addition operator which work with Test and an int.

01:28.290 --> 01:30.030
So the first hurdle has failed.

01:30.300 --> 01:32.760
The compiler has not been able to find an exact match.

01:33.540 --> 01:39.090
The compiler will then try to find a match, which involves converting the arguments. So it cannot do

01:39.090 --> 01:39.630
anything really

01:39.630 --> 01:43.980
with 5, but with test, it will see that there is a conversion to int.

01:44.700 --> 01:50.280
If it converts a Test to an int, then it has an addition which uses to ints, and the compiler knows

01:50.280 --> 01:50.940
how to do that.

01:52.470 --> 01:55.170
So the compiler will rewrite this expression.

01:55.440 --> 01:59.190
So instead of having a test, it has a call to test dot operator int.

02:00.180 --> 02:04.080
So that will return an int, and it all works nicely.

02:07.410 --> 02:08.520
So here is that code.

02:08.910 --> 02:13.620
We have our Test class with the int conversion operator. In the main() function,

02:13.620 --> 02:20.520
we create an object of this class and then we do something slightly different actually from the slide.

02:20.880 --> 02:21.660
Just for a change!

02:22.380 --> 02:24.780
So we are going to display the value of this object.

02:25.410 --> 02:31.140
Your first reaction is probably going to be that this will not work, because there is no left shift operator

02:31.140 --> 02:35.040
that uses a Test object. We will look at doing that later in the course.

02:35.670 --> 02:37.440
So if the compiler tries to do it that way,

02:37.440 --> 02:42.780
it will find there is function. But the compiler will look for the conversion to int, and the

02:42.780 --> 02:44.370
compiler knows how to output ints.

02:44.880 --> 02:47.470
So this is going to call test dot operator int.

02:48.840 --> 02:53.730
So we should get 42 on the screen. And it does work.

02:55.800 --> 03:01.080
This is known as an implicit conversion, because we did not explicitly ask for it.

03:01.530 --> 03:05.730
The compiler did it for us, or we allowed the compiler to do it for us.

03:06.570 --> 03:09.810
And generally, having things in code which are implicit is not good.

03:10.860 --> 03:16.170
If you are reading the code, they are not actually written in the code. You have to work out what would

03:16.170 --> 03:16.590
be there.

03:17.190 --> 03:20.910
And sometimes compilers may do different things from what you expect.

03:23.470 --> 03:27.760
This is a classic example that used to work in C++, but not anymore.

03:28.060 --> 03:29.650
We will see in a minute why it does not work.

03:30.790 --> 03:33.040
So you have an int and you do that.

03:33.550 --> 03:35.950
And yes, that is cin, not cout!

03:36.550 --> 03:39.640
And that would actually compile under older versions of C++.

03:40.690 --> 03:41.770
And the question is why?

03:42.280 --> 03:44.530
I mean, we are sending data to an input stream.

03:45.010 --> 03:46.090
How can that possibly work?

03:47.690 --> 03:49.040
The answer is actually quite subtle.

03:49.550 --> 03:52.330
The streams have a bool conversion operation.

03:52.850 --> 03:58.640
We have actually already used this, when we opened a file, and then we put the name of the file stream

03:58.640 --> 04:03.500
object inside an if statement. That actually called the bool conversion operator for the stream.

04:04.070 --> 04:09.380
And this operator will return true if the stream is in a good state and false if it is not in a good

04:09.380 --> 04:09.770
state.

04:10.520 --> 04:16.670
So that is how we checked if the file was correctly opened. So the compiler will see this.

04:17.720 --> 04:22.190
It will try to find a left shift operator that can work with these arguments.

04:22.910 --> 04:28.520
There is not one that works with input streams, but the compiler will see that it can convert this

04:28.520 --> 04:35.540
input stream to a bool. And then it can convert the bool to an int. The compiler can convert to a wider

04:35.540 --> 04:37.640
type, like bool to int ot int to double.

04:37.880 --> 04:43.580
There is no loss of data. And then it will need a left shift operator, which can work with two ints.

04:44.240 --> 04:45.140
And there is one.

04:45.410 --> 04:51.500
It's actually the ancient C left shift operator, for bit shifting. The one which is not overloaded

04:51.500 --> 04:52.160
for output.

04:53.210 --> 05:00.260
So this will compile and then it will left shift the state of the stream by 99 places and discard the

05:00.260 --> 05:02.870
result. Which is not very useful!

05:03.110 --> 05:05.090
But the point here is, there is no compiler ever.

05:05.150 --> 05:06.560
This is legal C++.

05:07.340 --> 05:12.020
So your program will run, and you get no output. In modern C++,

05:12.020 --> 05:13.310
you can prevent this from happening.

05:13.580 --> 05:15.890
You can make the conversion operator explicit.

05:16.700 --> 05:20.090
And this means that the conversion will only happen if you actually ask for it.

05:20.870 --> 05:25.160
And to do that, all you need to do is to put the "explicit" keyword before the operator.

05:28.960 --> 05:33.810
And then if we try to perform an implicit conversion, like that, we will get a compiler error.

05:34.480 --> 05:39.010
We need to explicitly say that we do want to cast this object to an int.

05:41.300 --> 05:43.100
So here is that code.

05:48.200 --> 05:50.900
We have our explicit conversion operator.

05:51.410 --> 05:56.090
So there is our implicit conversion. We are asking the compiler to do it for us.

05:58.710 --> 05:59.220
And there we are.

05:59.250 --> 06:05.430
We get an error, which is not a particularly helpful error, but the point is we do get an error.

06:06.000 --> 06:14.280
And then if we try it with the explicit cast, so we are saying here to the compiler, "you must convert

06:14.280 --> 06:15.270
this to int."

06:19.440 --> 06:21.990
And then it compiles and runs correctly.

06:23.730 --> 06:25.620
There is actually one exception to this.

06:25.860 --> 06:30.510
It's related to the bool that we talked about a minute ago. When we have an if statement and an object

06:30.510 --> 06:31.140
inside it.

06:32.160 --> 06:36.300
It would be rather inconvenient to have to put an explicit cast in something like this.

06:37.440 --> 06:43.860
So there is a rule saying, if it is a conversion to bool and it is in a conditional, then the conversion

06:43.860 --> 06:45.120
will be done without a cast.

06:45.840 --> 06:47.160
So you can just write it like that.

06:52.020 --> 06:54.990
And let's just check this, so I have taken the code we had before.

06:55.380 --> 07:04.050
I have added a conversion operator to bool. And then we have this extra conditional here. So let's see

07:04.050 --> 07:05.050
if this is allowed.

07:06.510 --> 07:09.060
And yes, it is allowed. It compiles and it runs.

07:11.130 --> 07:16.560
There is one more thing we need to look at with conversion operators. If you have a constructor with a

07:16.560 --> 07:20.940
single argument, that will also act as an implicit conversion operator.

07:21.840 --> 07:28.620
So here we have our Test class, with a constructor which takes a single argument, of type int, and this

07:28.620 --> 07:32.220
can be used to convert from int to a Test.

07:33.300 --> 07:39.930
So if we have a statement like this. We have an int, and we are using that to initialize a test object.

07:40.380 --> 07:46.320
What will happen here is that the compiler will actually create a temporary test object. It will call

07:46.320 --> 07:47.460
this constructor with argument

07:47.460 --> 07:53.040
4. That will produce a Test object, and then it will call the copy constructor.

07:53.790 --> 07:57.330
So we will have a new object, which is a copy of that temporary object.

07:57.690 --> 08:03.570
So sometimes this is useful, but it can also be a problem. If you have a function which takes a Test

08:03.570 --> 08:09.720
object as an argument and you pass it some literal or variable, which happens to be the same type as

08:09.720 --> 08:14.310
the argument to a single argument constructor, then instead of getting an error, you will actually

08:14.310 --> 08:15.810
get a silent conversion.

08:19.120 --> 08:21.830
So in C++ 11, you can actually turn that off as well.

08:22.120 --> 08:24.610
And the solution is the same: the explicit keyword.

08:25.360 --> 08:27.430
So you now make the constructor explicit.

08:27.880 --> 08:31.360
And that will prevent the conversion from happening.

08:33.500 --> 08:37.190
So if we try to perform an implicit conversion, we get a compiler error.

08:38.150 --> 08:41.450
Instead, we have to explicitly call that constructor.

08:45.520 --> 08:50.200
So here is that code. We have our Test class with the constructor taking a single argument.

08:51.160 --> 08:56.860
We have the first example where we try to initialize an object with the value 4. The compiler is going

08:56.860 --> 09:00.580
to perform an implicit conversion and create a temporary object.

09:03.720 --> 09:09.750
So there we are that compiles, but we may not have actually meant to do that. If we make the constructor

09:09.750 --> 09:10.380
explicit...

09:12.740 --> 09:16.760
So the compiler is now not allowed to perform that implicit conversion.

09:19.590 --> 09:20.550
And we get an error.

09:23.290 --> 09:28.120
"Cannot convert from int to test. constructor for class is declared explicit".

09:32.240 --> 09:34.730
So to do this, I have to actually create an object.

09:40.180 --> 09:43.930
And then there is no conversion. It is just a straightforward copy constructor call.

09:45.550 --> 09:47.500
Okay, so that is it for this video.

09:47.830 --> 09:48.730
I will see you next time.

09:48.910 --> 09:50.770
Until then, keep coding!
