- [Instructor] In the last lesson,
we discussed operator overloads
with member functions.
In this lesson, we'll look at why
and how you may sometimes use non-member functions
for operator overloads.
This is rational.cpp from chapter six
of the exercise files.
In the previous movie on overloading operators,
we overloaded the four basic arithmetic operators
with member functions
and you'll remember that this is what that looks like.
These are the operator overloads
and they're all members functions,
which means that I have this Rational:: here
and they're actually defined
in the class definition here,
in the class interface.
Now, if I come down to the end of our mains,
this is our main here,
and add a line, I'm just going to copy this line here
and instead of adding two rational objects,
I'm going to add a plus 14.
Just the integer 14.
And do we expect this to work?
Well, let's take a look.
I'm going to build and run.
And you notice that it works.
It actually works as expected.
Seven plus 14 is 21.
So that works.
Why does that work?
Well, if we come up here to our plus,
you notice that it expects a rational object
on the right-hand side.
We're not giving it a Rational object,
we're giving it a literal integer.
But if we look at our constructors,
you notice that our first constructor
is an implicit constructor
because it has default values.
So the numerator, it takes an integer
and it will take nothing for a denominator,
it'll substitute a one,
a default value for the denominator
and that's what's going on here.
We have what's called an implicit constructor,
which will accept an integer.
And so down here in the plus,
it actually creates a rational object.
It constructs an object
with that implicit constructor.
So if I were to come in here
and say cout
and take a look at the right-hand side,
you'll notice that it is a rational object
and when I go ahead and build and run here,
you'll notice that the right-hand side
of our addition is a rational object.
14 over one.
So that object has been implicitly created
by this operand in the addition operation.
Now, this works with the implicit creation
of the object on the right-hand side.
It does not work on the left-hand side.
If I say 14 plus a,
you'll notice that I get a compiler error
when I try to build this.
It says invalid operands to binary instruction,
int and Rational.
And the reason for this
is that all of our member function operator overloads expect
the object on the left-hand side
and that's because they are members of the class
and as such, the left-hand side
is the class itself,
is the object itself
that's being operated on.
So this whole scheme doesn't work
if it expects that implicit construction
on the left-hand side
and has an object on the right-hand side.
So the solution here
is to move this operator out of the class.
So I'm just going to remove that one
from the class interface there
and I'm going to come down here
and now this doesn't work anymore
'cause it's not in the class interface.
I'm just going to take all of this
and remove it and I'm going to come down here
just before main and I'm going
to create a non-member function operator overload.
So I'm going to take that out
because it's not part of the class anymore
and I'm going to give it two operands,
a left-hand side and a right-hand side.
And I'm going to make both of them rational references
like that and we don't need this const here anymore
because that only works for members functions.
And we don't need that anymore that we added.
Now we need to take each of these
and we need to make them work with the object interface.
So we can't even use n and d anymore,
we need to use the getters, numerator and denominator
because n and d are private
and we can't access them from outside of the class.
And so I'm going to say left-hand side
for all the ones that don't have a right-hand side.
And then I'm going to come back here
for all the numerators and I'm going to change 'em
to the getter.
I'll go ahead and I'll copy that.
And I'll do the same for the denominators.
Other than that,
the code remains the same
and I can build this.
Oh, I got a typo there.
I need to spell the class properly.
There we go.
And I can build this
and it builds, it succeeds
and I can run it
and you notice, we no longer have our error here
and now 14 plus the rational seven over one
is a rational 21 over one.
And so now the left-hand side
is being implicitly constructed
as a rational object
or rather this left-hand side
is being implicitly constructed
as a rational object
because it found a function
that will satisfy the function signature
that it's looking for.
There are definite circumstances
where you'll want to use non-member functions
for your operator overloads.
And C++ supports this as well.
In a nutshell, whenever you have a constructor
that allows implicit conversions,
you'll want to think about non-member overload functions.
These functions still go in your implementation file.