The last operators we'll overload in this section are the stream
insertion and extraction operators.
This will allow us to insert and extract our mystring objects
to and from streams exactly as we've been doing with all
the other built-in types.
You can see in this slide what the code would look like if we could
simply insert our own user-defined objects into an output stream.
This makes our classes feel and behave more like a built-in c++ type.
Of course, we can also overload the stream extraction operator so that
we can read data from a stream and assign them to our own objects.
Here you can see that we're reading data into Larry and Hero.
In this example and the one on the previous slide,
we're using cout and cin.
But we can use other streams as well as well as redirect cin
and cout to files and so forth.
Before we start, let's see why it really doesn't make sense to
implement the insertion and extraction operators as member methods.
Remember, when we overload an operator as a member method, the
left-hand side object must be an object of the class we're overloading.
This means that we would have to write Larry on the left-hand
side of the output statement.
While this will work, it would be very strange for c++ plus
programmers to use in this manner since it's not the way we use
these operators with other values.
The same is true for the extraction operator.
So we're going to overload these operators as non-member functions.
Let's overload the stream insertion operator first.
You can see that this is a non-member function named operator insertion
operator that has two arguments.
The first argument is an output stream object by reference.
This is typed as std ostream.
The second parameter is a reference to the mystring object whose data we
want to insert in the output stream.
Notice that the reference is constant.
Also notice that the function returns an output stream reference.
This is important because we want to be able to chain
insertions as we normally do.
It's important that we use ostream references, and
we don't copy the stream.
Then comes the easy part, put whatever data you like in whatever format you
like on the output stream as usual.
If this function has been declared as a friend function in the mystream
class, then you have access to all the private data members.
Otherwise, you have to use the public getters to get
the information you need.
And finally, the last step is to return the output stream reference.
That's it.
As you can see it's very simple and very useful too.
Now let's see how we can overload the stream extraction operator.
Let's start by looking at the function signature.
The name of the function is operator, extraction operator.
The function has two parameters.
The first is a reference to an input stream whose type is istream.
And the second is a reference to the object we want to extract data into.
Notice that since we're going to modify this object, we
don't want it to be a const.
So depending on the data we want to read, we can get the
data from the input stream and either store it locally or
store it directly in the object.
In this case, we allocate a large array of characters that
will hold the data we want to construct a mystring object.
Then we simply create a temporary mystring object and assign it back
to the object that was passed in.
This assumes we have copied or moved overloaded assignment operators,
and they're implemented correctly since we have a raw pointer.
Finally, we return the istream reference so that
we can change assign.
We can do all sorts of error checking and setting and getting
the state of the input stream so we have control of the data we're
extracting as well as not overrunning the size of the buffer we created.
Now let's head over to the IDE and implement these two
operators in the mystring class.
Okay, so I'm back in the IDE.
I'm in the section 14 workspace in the MyString-insertion-extraction project.
And what I've got here is I've got the my string class again.
And I've gotten rid of all the operators that we've
overloaded previously just so it's a bare bones class again.
And the reason I did that's just to make this a little bit more readable.
And what we want to do here is overload the insertion and extraction
operator, so we can use this these objects with streams really easily.
So here's a sample main that's going to test this.
And you can see here I'm creating Larry and Moe as my strings and
Curly is an empty string right now.
And I'm outputting enter the third stooge's first name.
I'm reading from standard n, in this case, cin into Curly.
So we're overloading the out operator right there to
work with mystring object.
Then I'm displaying the three stooges are Larry Moe and Curly.
Again, we're using the insertion operator here that
we're going to overload.
And then we're going to grab all three of the stooges names.
So we say enter the three stooges names separated by a space, and
we'll type in whatever we like.
They'll be stored into Larry Moe and Curly.
And then we'll display them out again.
Okay, so pretty simple.
And you can see this this main driver here looks nice.
Now we don't have all those dot display methods that we had before.
Cool, so let's go to mystring header file.
And let's get started here.
First thing we want to do is I'm going to implement
these as friend functions.
So the class is going to declare them as friends.
So why don't we do that first.
And what we can do here is just simply say friend and provide the prototype.
So we've got we're returning a std ostream reference.
We'll do the insertion operator first.
So we've got a reference.
The operator we're overloading is the insertion operator.
And it's a binary operator.
So we've got two parameters here.
The first one is a std ostream.
And we can call this anything we like.
We can call it os or out, typically those are the names that are used.
And we've got a mystring, a const my string reference.
And we'll just call that right-hand side.
We'll stick to that naming convention.
So that takes care of that prototype.
And now we'll do the extraction operator, so same idea friend.
In this case, we're returning an input stream by reference again.
And the operator is operator.
And we'll be doing the extraction operator.
And again, we've got two parameters the first one is
the input stream by reference, and we'll just call that in.
And we've got a my string object also by reference
called it right-hand side.
Notice how this one is not const because I do want to modify
that object based on what I'm reading in from the input stream.
Okay, so that's it.
Those are our two function prototypes.
And now what we can do is we can go to the implementation
file or mystring cpp file, and we'll actually write these.
I'm going to put them all the way down at the bottom here.
That way I've got a lot of room to work.
So let's say that this is the overloaded insertion operator.
Let's do that one first.
All right, so same type of function prototype, right.
Instead, ostream reference, the operator we're overloading
is the insertion operator.
And we've got the same two parameters that we had before.
We've got an ostream reference.
And we called it os, I believe.
Yes, we did and a const mystring class by reference right-hand side.
There we go.
Okay, so now this is probably one of the simplest methods to implement.
All we're doing is we're putting on os.
Remember, this is a friend.
So we can simply say right-hand sides str.
That's it.
If this wasn't a friend, we could use the get str method.
And then we're going to return that output stream.
That's it. Pretty straightforward.
Now let's overload our extraction operator.
And we'll do the prototype again here.
So it's a stood istream reference.
The operator we're overloading is the extraction operator, and we
also have two parameters, right.
The first one is a std istream reference.
And we'll just call that in.
And we've got the mystring ref right-hand side, again, this one
can't be const because we're going to read into it or change it,
that's it, so now we're going to get a string from the input stream.
We need to store that somewhere.
So let's create a pretty big size buffer here.
And we'll do this dynamically on the heap.
We'll just store a 1000 characters.
That should give us plenty of room.
We could certainly do this in different ways so that we
don't overrun this buffer.
But let's just do it like this because it's a simple example to understand.
Now we get whatever's in the input stream and we store it in buffer.
Right now we've got the buffer, it's got the data we have -- we want.
And what we want to do is we want to update this right-hand side objects
string based on this data, right.
So there's a lot of ways to do this.
One of the simplest ways to do it is just to say RHS equals mystring
and initialize it with buff.
Okay, now depending on whether you've got copy assignment or move
assignment, that's what's going to happen here, we've got both.
So this is going to use move assignment which is
super-efficient we're just going to steal that pointer.
When we're done, we make sure that we delete this temporary
storage that we created in buff.
And we return the input stream.
Remember, this is going to return it by reference.
And that's it.
We should be done.
Let's run this and see if we have any typos.
And we do.
I spelled operator incorrectly, I believe, I sure did.
I'll fix that real quick.
Let's see if there's any other errors down here.
I think they're all related to that same error.
So let's run this.
And here we go.
Enter the third stooge's first name.
Well, the third stooge is Curly.
Notice we use the move assignment, which is what we expected.
That move assignment happened when I copied that object out.
Now it says enter the three stooges names separated by a space.
Well, let's just give them different names.
Let's say it's frank, Jim and Joe.
So you can see three move assignments there.
And it says the three stooges are Frank, Jim and Joe.
So there you go.
We've overloaded the insertion and the extraction operators to work with
our classes, and it really feels like it's part of the type system now.
All right, so that's it for this section.
The next part is the challenge exercise, so I'll see you there.