- [Instructor] Operator overloading is the ability
to use common operators
with user-defined objects and classes.
It's not unique to C++,
in fact, it was one of the original concepts
borrowed from ALGOL for C++.
But how C++ does it is fairly unique
and extremely powerful.
There are two distinct ways
to overload operators in C++ with member functions
as part of a class definition
and as separate non-member functions.
In this lesson, we'll discuss operator member functions
in your class definitions, and we'll discuss
the operator non-member functions in the next lesson.
Here is a working copy of rational.cpp
from chapter six of the exercise files.
This is a simple, rational number class that performs
four function arithmetic on fractions.
Here, we have the class definition.
We have two data members for a numerator and a denominator,
and you'll notice their default values
are zero for the numerator and one for the denominator.
And we have two constructors.
The first constructor you'll notice has default values,
and this is something new.
We haven't seen this before.
This makes this an implicit constructor
because you can give it no arguments, whatsoever,
and if you do, then the arguments get these default values.
And so here, you see that the numerator default value
is zero and the denominator default value is one.
And then we initialize them with this
initializer list, as we've seen before,
and there's also a copy constructor.
And we've seen how copy constructors work, before.
Then there's a destructor, there's getters
for the numerator and denominator,
there's an assignment operator,
and there's a few utility functions
for reducing a fraction to its lowest common denominator,
returning formatted and non-reduced STL strings.
And then you see the four function operators.
The function signature for an operator
includes the keyword operator
and then the symbol for the operator.
And here, we have member functions
for the four common, four function arithmetic operators:
addition, subtraction, multiplication, and division.
You'll notice that each of these returns a rational object.
So let's take a look at the code for the addition operator.
We'll scroll down, here.
And you see, it's very simple, we perform the addition
on the fraction and we return a new rational object.
And we're not returning a reference in this case,
we're actually returning a new rational object,
which is constructed from the arithmetic formula
for adding two fractions.
And likewise, the subtraction operator,
the multiplication operator, and the division operator,
all work in the same way.
So, let's go ahead and take a quick look at our main,
and we can see why we're doing this.
You'll notice I'm using cout for this,
and there's a reason for that
that we'll get to in a little bit.
For now, Just notice that I construct a rational object,
in this case, with just one argument.
And so remember the default denominator is one
so that we're never dividing by zero.
And so I'm assigning a value of seven
to the rational object A.
And B is 25 15ths, which is the same as five-thirds.
C uses the copy constructor, so it's the same as B.
D uses the default constructor,
so it will be zero over one.
And then we assign C to D
and we create a reference E,
and then we assign it to itself.
So we're kind of testing out all of the different ways
that we can use this rational object.
But then, we get down here
and you see we're actually doing arithmetic.
And so we have A plus B,
we have A minus B,
A times B, and A divided by B.
So let's go ahead and run this
and see how all of this works.
So I assigned A equals seven, and you notice A is,
and it says seven over one.
So why is it printing seven slash one?
Why is it printing that string?
You notice here, I have a non-member function
which is overloading the left shift operator
for the specific purpose of using it with cout.
And this, again, is very common.
This is because cout does that strange thing
with the left shift operator
we've talked about, before.
And so this is the standard way to implement
the cout stream for a custom object.
On the right-hand side, I have my rational object,
on the left-hand side, I have an ostream,
which is the stream that's used for cout.
And so I'm actually overloading the left shift operator
in the same way that I'm overloading
operators as member functions.
And we'll talk more about non-member function overloads
in the next lesson, but I wanted to see how this is done.
And basically, it's just using this raw string
member function, which we define up here.
And raw string looks like this.
We simply return to string of the numerator
and a slash character, and to string of the denominator.
And so whenever we use our object on the right-hand side
of a left shift operator with an ostream on the left side,
for example, cout, then we get that raw string.
So you see A is seven slash one,
B is 25 slash 15 because I've initialized it
with the 25 for the numerator
and a 15 for the denominator.
C is the same as B.
D, just a default constructor, is zero over one.
And then we assign C to D, so it gets that same 25 over 15.
And then we take a reference of D
as E and we get that same value for E.
Here, I'm using the string version
which does the reduction of the fraction.
And you see D is now one and two-thirds
instead of 25 15 and we have this string function
up here, which calls reduce.
And here's the reduce function
which finds the lowest common denominator of a fraction.
And the string function will actually
split out any part where the numerator
is greater than the nominator, so we get the whole number
with the remainder fraction.
So this is our result.
And down here, we finally do our arithmetic.
And you can see that seven plus 25 15ths is that,
and we get these results.
One of the advantages of this cout is that we can
put whatever we want, here.
So we can use our string function, instead.
And if I save this and run it,
now we get all of our reduced strings
as our default readout with cout,
and we can see how useful that is, as well.
So I know that's a lot to take in and we're going
to get into more details in the next lesson.
Operator overloading is a fundamental part of C++.
It's as easy to do as defining a class method.
And we'll look at non-member functions
for operator overloading in the next lesson.