In the previous video, we saw how we can overload operators
using class member methods.
In this video, we'll learn how to overload operators using
non-member or global functions.
Since these are not member functions, we no longer have a
this pointer referring to the object on the left-hand side.
So since we very often need access to private attributes in the objects,
you see these non-member functions declared as friend functions of
the class in many applications.
This isn't absolutely necessary since we can still use getter
methods to access attribute values.
But as I said, you often see them implemented as friends.
I'm going to declare these overloaded operator methods as friends
when we head over to the ide.
So in the case of unary operators, a single object
is in the parameter list.
And in the case of a binary operator, two objects are in the parameter list.
So let's overload the unary minus operator to make a string lowercase
as we did in the previous video.
We want to provide the same functionality we did before,
and our use of the unary minus operator would look the same.
Let's see how we can do this using a non-member function.
In this slide, I'm assuming that this function has been declared
as a friend to the mystring class since I'm directly accessing
the private attribute str.
Notice first that this is not a member function,
it's a regular c++ global function.
The function returns a mystring object by value, and it's
named operator minus, and it expects a single parameter.
In this case, obj is a mystring object reference.
Now the code is essentially the same as it was in the member version
except that the string data is in obj.str rather than in this str.
We allocate storage on the heap, copy the object's string
data, loop through and make the copied string all lowercase.
Then we create a new mystring object using the lowercase string
as the initializer, de-allocate the temporary storage and
return the newly created object.
Of course, you can't have both the member and non-member versions
of this overloaded operator at the same time or the compiler
wouldn't know which one to use.
You can only have one or the other.
You probably already figured out that overloading binary operators
as global functions is basically the same except that now we have two
arguments required by the function.
The first argument is the left-hand side object and the second is
the right-hand side object.
Here you can see some example prototypes for some operators.
Notice that they all have two parameters in the parameter list.
I've named the first LHS for left-hand side and the second
RHS for right-hand side.
Then at the bottom of the slide, you can see how these operators
can be used and the functions that c++ will call when it uses them.
Let's see how we can overload the equality operator as
a non-member function.
Again, I'm accessing a private attribute str in the mystring class.
So I'm assuming this function is a friend of the mystring class.
The code is almost the same as it was for the member version except
that now I have an LHS object instead of the this pointer.
So we compare the left-hand side string to the right-hand side string
using string compare as we did before.
It's as simple as that.
Finally, let's overload the binary plus operator so that we can use it
to concatenate two mystring objects.
We create Larry Moe and Stooges as mystring objects,
as we did previously.
Now when we use the plus operator, notice the methods that the
compiler is calling in the comments.
Also notice that each is called with two arguments as we expect.
Finally, remember that with the member version, the left-side argument had
to be an object of the class type.
With non-member functions, this isn't the case.
Either one or both arguments can be of mystring type.
However, if you have two string literals that won't work.
C++ assumes primitive pointer and not objects.
So let's implement concatenation as a non-member function in the next slide.
Here you can see that the function operator plus returns
a mystring object by value.
It also expects two mystring objects left-hand side and right-hand side.
Notice that they're both constant references since we
don't want to modify them.
The code now is exactly as it was for the member version
except that whenever I need the left-hand side object I use LHS
instead of the this pointer.
That's it.
Again, both the member and non-member versions achieve the desired result.
But remember, you can only use one at a time.
Let's head over to the ide and overload some binary operators
as non-member functions.
Okay, so we're back in the ide.
I'm in the section 14 workspace, and the project is
mystream-operator-functions.
This is the project where we're going to implement those
three overloaded operators: the equality operator, the unary minus
operator, which makes the string lowercase and the plus operator,
which concatenates two strings.
And this time, we're going to implement them as non-member
functions or global c++ functions.
First thing we're going to do is we're going to make them friends.
We don't have to make them friends.
But it's going to be a lot easier to write the code because they don't have
to call those getters all the time.
So we can do that right in the class.
Remember, the class has to grant friendship.
So we'll write the function prototypes here, and we'll
start them off with friend.
And we'll do the first one.
The first one is returns a Boolean.
The operator is the equality operator.
And remember now since this is not a member function, we
need two parameters, right.
This is a binary operator.
So the first one will be const mystring ref LHS for left-hand
side and const mystring ref right-hand side, right.
So that's one function prototype.
We'll do the next one for the unary minus.
So again, friend -- this will return a mystring object by value the
operator, we're overloading is the the minus operator, the unary minus.
And it expects a single mystring ref.
And we could call this obj.
We can call this anything we like.
I think I called it obj in the slide, so I'll call it obj here.
And then we've got another operator that we want to overload.
In this case, it returns a mystring object by value again, and this
is the concatenation operator.
So it's going to be the plus operator, and it's a binary operator.
So we've got const mystring ref left-hand side and const
mystring ref right-hand side.
Okay, so there we go.
It doesn't really matter where you put these friend declarations in,
doesn't matter if you put them in the private area, the public area.
It doesn't matter.
So there we go.
Unless I have any typos that looks pretty good.
Now what we'll do is we'll go to the mystring cpp and implement those.
We can really implement them anywhere.
But since they really add to the interface of the class, it's
common practice to implement them right in here in the .cpp file.
I'm going to implement them here at the end.
So let's do the first one.
Let's do the equality.
And again, this is a regular function, it's not a member function.
So we're going to say bool operator, double equal sign for the equality.
This is a binary operator, so it expects same prototype we did
before, mystring ref left-hand side const mystring ref right-hand side.
Okay, so now we'll write the code.
We're going to return.
We're going to call std string compare.
And what are we comparing, we're comparing the left-hand sides string
to the right-hand side's string.
See the difference between this one and the member function.
The member function, we really didn't have this guy here.
That was the this pointer.
So we did this str or simply str.
But here we've got those two objects, so that's what we're going to do.
So we're going to compare this to 0, and that's what we're going to return.
And that should be done.
Great.
Now let's do the make lowercase.
Notice again, this is not a member function.
If it was a member function, it would look something like that, right.
It's not.
This is just a regular global function.
So here's make lowercase.
Make lowercase returns a mystring object by value.
It's operator minus the unary operator we're overloading.
And since it's unary, there's going to be one parameter
in this parameter list.
And it's going to be a mystring ref and we'll just call this obj.
I think that's what I called it in the slides, and I'll stick to that name.
That's it.
Now let's write the code again.
Again, it's the same code we had before.
We need a buffer area.
And what we're going to do is we're going to allocate a new array of
characters in that buffer area.
How big?
Well, we're going to ask std strllen to give us the length of.
Again, what is this now, it's obj.str.
Right now we have access to that because we're a friend.
And we're going to add the one for the string terminator.
Now that we've allocated the space, we're going to string copy
into the buffer from obj str.
Again, that function copies one character at a time.
And then when it hits the terminator, it copies that as well and stops.
That's it.
Now we'll loop through just like we did before.
So we'll go from an unsigned int, i equals 0 while I is less than, we'll
say, std string length of buff by one.
And for each iteration what we'll do is, we'll just simply say buff sub-I
equals, we'll call std to lower, and we'll make the buffs of I lower.
That just makes it a lowercase character, right.
So now we've got what we need to build our temporary object,
temporary to this function that we're going to return.
So mystring temp will initialize it from buff, and we'll return
buff sorry we'll return temp.
Now obviously, we allocated space in here, which we're done with.
So we need to delete buff.
That way we don't leak memory.
And I think that should do it again.
If we have some typos I'll fix them once I compile.
And then the last one we'll do is the concatenation.
So now let's implement this one.
It's going to return a mystring object.
The operator we're overloading is the addition or plus operator, which
means concatenation in this context.
And we've got it's a binary operator, right.
So we've got those two objects again in the parameter list,
the left-hand side and the right-hand side, both references.
Okay, so now what do we do?
Well, let's allocate the space.
Remember, the space needs to be big enough to hold both those strings
since we're going to concatenate.
So we'll just simply say char buffer again, and we'll
create a new character array.
How big is it?
Well, it's the length of left-hand side string plus the length of the
right-hand side string plus one.
That way we've got enough space to put both strings in there.
Now what we do is we just copy the first one over.
We use string copy into buff from the left-hand side object,
and then we concatenate on the end of that using string cat
from the right-hand side object.
Again, we've got what we need to create our object that
we're going to return now.
So we'll create mystring, and we'll just call it temp, and
we'll initialize it with buff.
And let me get rid of that space in there.
Perfect, again, we return temp.
But before we do that, we've got to be sure that we delete the buffer.
So we don't leak memory.
And that should do it.
So let's give this a compile, and we've got a compiler error here.
I need one more colon there.
And I've got an extra parenthesis and see what else we have here, char.
And that should do it.
There's my run.
So what we're doing is we're creating a string Larry, which is Larry with an
uppercase l, and we're displaying it.
There you can see it.
Then we're using the unary minus operator right here.
And we're negating Larry.
What that means is just make Larry with all lowercase letters.
And in this case, we're assigning right back to Larry.
So what happened here is that you can see there he prints out right here,
and we're using move assignment.
So Larry has got a lowercase l now.
And then we've got some some comparison operators
that we're testing out here.
So Larry right now is Larry and Moe is Moe.
Are they the same?
No.
Is Larry the same as Stooge.
Yes, because I assigned Larry to stooge as you can
see, so they're the same.
And then we've got a few more test cases here, which are real simple.
Here Larry plus Moe displays Stooges is Larry plus Moe.
So when I display Stooges, you see here Larry Moe, right.
No space between them because I didn't provide one.
Here two Stooges is Moe plus space plus Larry.
And I display that, there you see Moe and a space and Larry.
And then finally, we're going to change some of these concatenators so
we have Moe space Larry space Curly.
And we've got Moe Larry and Curly.
Notice Larry still has that little lowercase l, and curly is a c-style
string, and it works just fine.
Okay, there you go.
You'll have some more time to practice these in the challenge exercise where
you'll be able to do some overloaded member functions and some overloaded
operators as member functions and others as non-member functions.