#ifndef RAT2_H
#define RAT2_H
#include < iostream >
using namespace std;
Consider the class definition. The private members are the same:
numerator, denominator,
and the
reduce()
function.
And notice that the constructor is identical to the simple Rational class,
having two parameters, both with default values.
Temporarily skip over the friend declarations.
Let's consider the arithmetic operators first: operator+
,
operator-
, etc. first.
Rational operator+(const Rational &) const;
Rational operator-(const Rational &) const;
Rational operator*(const Rational &) const;
Rational operator/(const Rational &) const;
  z = x + y;
  const Rational c(1,2);
  Rational x(7,8), y;
  y = x + c;
  const Rational c(1,2);
  Rational x(7,8), y;
  y = c + x;
if (x == y)
...
that this is the same as
if (x.operator==(y))
...
Notice that the assignment operators are slightly different:
Rational& operator+=(const Rational &);
It makes sense that there is no const at the end, because you are
changing the current object. The code
y += x;
is the same as
y.operator+=(x);
so the current object, y, is getting changed. The return type is
  Rational&   (returning a reference to a Rational object)
primarily because the thing you're changing exists outside the function,
i.e., isn't local, and it's more efficient to simply copy back the address
than make a copy of the whole object (which is what happens when you return
a Rational object). It's similar to fake pass-by-value when you pass in
the address/reference instead of making a copy of the object.
cout << x;
which is the same as
cout.operator<<(x);
The left operand will always be some stream object like cin or cout
and will never be a Rational object or whatever your class is.
So   operator<<   and   operator>>   can never
be members of the class. And yet they need to do input and output
which always involves private data members. Sure you could write
lots of accessor functions or write some public function that does
the same thing and call it, but that's not very elegant.
friend ostream& operator<<(ostream&, const Rational&);
friend istream& operator>>(istream&, Rational&);
The keyword friend says
that the functions are friends of the class. And friends get
to access the class' private members. Yes, no non-humorous
way to say that. Friends can access your private members.