Hello again! In this video, we are going to look at conversion operators. A conversion operator
is a member function that converts an object of the class into some other type.
So, in a way, it is like being able to define your own casts for your classes.
A class can define a conversion operator.
It is a member function, which converts an object of the class to some other type.
It can be any other type we want, and we can do the conversion however we want to. With our Test class,
we can define a conversion operator to int. The name of this function
will be operator int. It takes no arguments.
We make it const because we do not want to modify the object.
We are just returning its value in a different form.
That is all.
And then inside the body of the function, we return some value of this type.
In this case, we are just going to return the int member.
And then, whenever we use an object of this class where an int is expected or could be used, then the
compiler will add a call to this conversion operator.
For example, if we have something like this. We have an object of our class and we add 5 to it.
The compiler will have to find a function that can resolve this call.
So it is obviously going to be some sort of addition
operator. The compiler does not know about any addition operator which work with Test and an int.
So the first hurdle has failed.
The compiler has not been able to find an exact match.
The compiler will then try to find a match, which involves converting the arguments. So it cannot do
anything really
with 5, but with test, it will see that there is a conversion to int.
If it converts a Test to an int, then it has an addition which uses to ints, and the compiler knows
how to do that.
So the compiler will rewrite this expression.
So instead of having a test, it has a call to test dot operator int.
So that will return an int, and it all works nicely.
So here is that code.
We have our Test class with the int conversion operator. In the main() function,
we create an object of this class and then we do something slightly different actually from the slide.
Just for a change!
So we are going to display the value of this object.
Your first reaction is probably going to be that this will not work, because there is no left shift operator
that uses a Test object. We will look at doing that later in the course.
So if the compiler tries to do it that way,
it will find there is function. But the compiler will look for the conversion to int, and the
compiler knows how to output ints.
So this is going to call test dot operator int.
So we should get 42 on the screen. And it does work.
This is known as an implicit conversion, because we did not explicitly ask for it.
The compiler did it for us, or we allowed the compiler to do it for us.
And generally, having things in code which are implicit is not good.
If you are reading the code, they are not actually written in the code. You have to work out what would
be there.
And sometimes compilers may do different things from what you expect.
This is a classic example that used to work in C++, but not anymore.
We will see in a minute why it does not work.
So you have an int and you do that.
And yes, that is cin, not cout!
And that would actually compile under older versions of C++.
And the question is why?
I mean, we are sending data to an input stream.
How can that possibly work?
The answer is actually quite subtle.
The streams have a bool conversion operation.
We have actually already used this, when we opened a file, and then we put the name of the file stream
object inside an if statement. That actually called the bool conversion operator for the stream.
And this operator will return true if the stream is in a good state and false if it is not in a good
state.
So that is how we checked if the file was correctly opened. So the compiler will see this.
It will try to find a left shift operator that can work with these arguments.
There is not one that works with input streams, but the compiler will see that it can convert this
input stream to a bool. And then it can convert the bool to an int. The compiler can convert to a wider
type, like bool to int ot int to double.
There is no loss of data. And then it will need a left shift operator, which can work with two ints.
And there is one.
It's actually the ancient C left shift operator, for bit shifting. The one which is not overloaded
for output.
So this will compile and then it will left shift the state of the stream by 99 places and discard the
result. Which is not very useful!
But the point here is, there is no compiler ever.
This is legal C++.
So your program will run, and you get no output. In modern C++,
you can prevent this from happening.
You can make the conversion operator explicit.
And this means that the conversion will only happen if you actually ask for it.
And to do that, all you need to do is to put the "explicit" keyword before the operator.
And then if we try to perform an implicit conversion, like that, we will get a compiler error.
We need to explicitly say that we do want to cast this object to an int.
So here is that code.
We have our explicit conversion operator.
So there is our implicit conversion. We are asking the compiler to do it for us.
And there we are.
We get an error, which is not a particularly helpful error, but the point is we do get an error.
And then if we try it with the explicit cast, so we are saying here to the compiler, "you must convert
this to int."
And then it compiles and runs correctly.
There is actually one exception to this.
It's related to the bool that we talked about a minute ago. When we have an if statement and an object
inside it.
It would be rather inconvenient to have to put an explicit cast in something like this.
So there is a rule saying, if it is a conversion to bool and it is in a conditional, then the conversion
will be done without a cast.
So you can just write it like that.
And let's just check this, so I have taken the code we had before.
I have added a conversion operator to bool. And then we have this extra conditional here. So let's see
if this is allowed.
And yes, it is allowed. It compiles and it runs.
There is one more thing we need to look at with conversion operators. If you have a constructor with a
single argument, that will also act as an implicit conversion operator.
So here we have our Test class, with a constructor which takes a single argument, of type int, and this
can be used to convert from int to a Test.
So if we have a statement like this. We have an int, and we are using that to initialize a test object.
What will happen here is that the compiler will actually create a temporary test object. It will call
this constructor with argument
4. That will produce a Test object, and then it will call the copy constructor.
So we will have a new object, which is a copy of that temporary object.
So sometimes this is useful, but it can also be a problem. If you have a function which takes a Test
object as an argument and you pass it some literal or variable, which happens to be the same type as
the argument to a single argument constructor, then instead of getting an error, you will actually
get a silent conversion.
So in C++ 11, you can actually turn that off as well.
And the solution is the same: the explicit keyword.
So you now make the constructor explicit.
And that will prevent the conversion from happening.
So if we try to perform an implicit conversion, we get a compiler error.
Instead, we have to explicitly call that constructor.
So here is that code. We have our Test class with the constructor taking a single argument.
We have the first example where we try to initialize an object with the value 4. The compiler is going
to perform an implicit conversion and create a temporary object.
So there we are that compiles, but we may not have actually meant to do that. If we make the constructor
explicit...
So the compiler is now not allowed to perform that implicit conversion.
And we get an error.
"Cannot convert from int to test. constructor for class is declared explicit".
So to do this, I have to actually create an object.
And then there is no conversion. It is just a straightforward copy constructor call.
Okay, so that is it for this video.
I will see you next time.
Until then, keep coding!