d
and
e
with the same notation we would use for the built-in types such as
int.
operator+,
operator++,
operator+=,
etc.
Later in the course we will have another motivation for operator overloading: it will allow our templates to be applicable to the data types we invent.
//column 1
#include <iostream>
#include "date.h"
using namespace std;
date d;
d.next();
d.next(280);
date e {d};
e.next(7);
int n {distance(e, d)};
date midpoint {d};
midpoint.next(n/2);
if (equals(d, e)) {
d.print();
d.next();
d.print();
d.print();
cout << "\n";
d.next();
d.print();
cout << "\n";
|
//column 2
#include <iostream>
#include "date.h"
using namespace std;
date d;
++d;
d += 280;
const date e {d + 7};
int n {e - d};
const date midpoint {d + n/2};
if (d == e) {
cout << d;
cout << ++d;
cout << d << "\n";
cout << ++d << "\n";
|
//column 3
#include <iostream>
#include "date.h"
using namespace std;
date d;
operator++(d);
d.operator+=(280);
const date e {operator+(d, 7)};
int n {operator-(e, d)};
const date midpoint {operator+(d, n/2};
if (operator==(d, e)) {
operator<<(cout, d);
operator<<(cout, operator++(d));
operator<<(operator<<(cout, d), "\n");
operator<<(operator<<(cout, operator++(d)), "\n");
|
operator
function can often do most of its work by calling a second operator
function.
This means that the first function will not need to be a member
function or a friend.
operator
function needs to construct a new object
(e.g.,
operator+,
postfix operator++),
it can often do this by receiving an argument via pass-by-value.
operator
function be a member function, a friend function, or neither?
operator
function accepts an argument that is an object,
should the object be passed by value or by reference?
operator
function?
date
which we will provide with overloaded operators:
c++ date.C main.C ls -l a.out ./a.out
<<
already accepts an object of class
ostream
(such as the object
cout)
as its left operand.
We will now let the operator
accept an object of class
date
as its right operand:
#include <iostream> //for the object cout #include "date.h" //for class date using namespace std; //because cout belongs to namespace std date d; //Call the default constructor. cout << d; //cout is the left operand, d is the right operand.We will have to create a function named
operator<<.
date.
Therefore this function
must be a member function or a friend of class
date.
But our
operator<<
cannot be a member function of class
date.
In C++,
when an operator is implemented as a member function,
it always has to be a member function of its
left
operand.
In this case, the left operand of
<<
is
cout.
Therefore,
in order to be able to mention the private member(s) of class
date,
operator<<
will have to be a friend of class
date.
When we write the above expression
cout << d;the computer will behave as if we had called the following two-argument friend function of class
date.
operator<<(cout, d);
cout
and d
as arguments to the function
operator<<,
we don’t need to create copies of these two objects.
Therefore both arguments will be passed by reference.
Our
operator<<
function will perform output,
and the act of peforming output
changes the value of the object
cout.
Therefore cout
will have to be passed to operator<<
as a non-const reference.
We want to guarantee that we can output a date
object without changing or damaging it,
so the date
object will have to be passed to
operator<<
as a const reference.
Finally, the value of the expression
cout << d
must be
cout,
so that we can use the expression
cout << d
as part of a
larger expression.
cout << d;
cout << d << "\n";
+=
already accepts an int such as 7
as its right operand.
We will now let the operator accept an object of class
date
as its left operand:
#include <iostream> #inlcude "date.h" using namespace std; date d; //Call the default constructor. d += 7; //Change d to the date that's a week from today. //d is the left operand, 7 is the right operand. cout << d << "\n";
//Why the operator += is simpler than the operator +
int i {10};
i += 10; //This += merely changes the value of an existing variable.
//This + creates a new (invisible) int variable, born holding 30.
cout << i + 10 << "\n";
operator+=
needs to mention the private members of class
date.
Therefore it must be either a member function or a friend function of class
date.
It could be a member function of class
date,
because this time the date
object is the left operand of the
+=.
And since the
operator+=
function
will use the private members of only one object of the class,
we will make it a member function of class
date.
It will be short enough to be an inline member function.
d += 7
must be the new value of d,
so that we can use the expression
d += 7
as part of a
larger expression.
cout << (d += 7); //Parentheses force the += to execute before the <<
The function
operator+=
must therefore return the
date
object that the function belongs to.
Unsurprisingly,
this
date
object is *this.
To return this
date
object without creating a copy of it,
we return it by reference.
Four more operator functions can be easily implemented by calling the
inline member function
operator+=
that we just wrote.
These four functions are two different “flavors” of
operator+,
and two different flavors of
operator++.
+
already accepts operands of lots of different combinations of types.
date
object as its left operand and an
int
as its right operand.
int
as its left operand and a
date
object as its right operand.
#include <iostream>
#inlcude "date.h"
using namespace std;
date d;
date nextWeek {d + 7}; //left operand is date, right operand is int
date nextYear {365 + d}; //left operand is int, right operand is date
cout << (d + 14); //Can also use d + 14 in a larger expression.
date.h
contains four definitions of the function
operator+,
but the first two are for pedagogical purposes only.
Our first pedagogical example mentions the private data member day,
so it has to be a member function or friend.
I made it a member function,
because it uses only one object of class date.
Our second pedagogical example does its work without mentioning the name of any private member of the class. Therefore this function does not need to be a member function or a friend. It’s still a member function, but unnecesarily so.
Our last two definitions of
operator+
are neither member functions or friends,
and are therefore defined outside and below the
{curly
braces}
of the class definition in
date.h.
An inline function is automatically static,
so this .h
file can be
#included
in multipe .C
files of a C++ program without incurrin the “multiple definition”
error.
operator+
function must create and return a new object of class
date.
The pedagogical examples create a new object
by explicitly creating a
copy
of the object they belong to.
The non-pedagogical examples create an object in an easier way,
simply by using pass-by-value to create a copy of the object that
was passed to them.
operator+
returns the new object it created.
Unfortunately, we must create and return a
copy
of this new object,
because the new object dies when the
operator+
function returns.
To make sure that no one tries to change the new object,
the return value is a const
object:
date d; //Can use the value of the new object returned by operator+ //(This invisible object is called a "temporary".) cout << (d + 7) << "\n"; //but cannot change the value of the new object returned by operator+ (d + 7) += 365;
operator+
is
++
operator already accepts an operand of type
int
(and other types too).
We will now let the operator accept an operand of type
date.
#include <iostream>
#include "date.h"
using namespace std;
date d;
cout << d << "\n"; //today
++d;
cout << d << "\n"; //tomorrow
cout << ++d << "\n"; //the day after tomorrow
date.h
contains three definitions of the function
operator++,
but the first two are for pedagogical purposes only.
Our first pedagogical example mentions the private data member
day,
so it has to be a member function or friend.
I made it a member function, because it uses only one object of class
date.
Our second pedagogical example does its work without mentioning the name of any private member of the class. Therefore this function does not need to be a member function or a friend. It’s still a member function, but unnecesarily so.
Our last definition of
operator++
is neither a member function nor a friend,
and is therefore defined outside and below the
{curly
braces}
of the class definition in
date.h,
just as we did for the final definitions of
operator+.
operator++,
like operator+=,
does not create any new object.
It merely modifies the value of an ixisting object,
and then returns the existing object without making a copy of it.
operator++ is
++
operator already accepts an operand of type
int
(and other types too).
We will now let the operator accept an operand of type
date.
#include <iostream>
#include "data.h"
using namespace std;
date d; //Default constructor puts today into the newborn object.
cout << d++ << "\n"; //Outputs today, leaves d holding tomorrow.
cout << d << "\n"; //Outputs tomorrow.
date.h
contains three definitions of the function for postix
operator++,
but the first two are for pedagogical purposes only.
Our first pedagogical example mentions the private data member
day,
so it has to be a member function or friend.
I made it a member function,
because it uses only one object of class
date.
Our second pedagogical example does its work without mentioning the name of any private member of the class. Therefore this function does not need to be a member function or a friend. It’s still a member function, but unnecesarily so.
Our last definition of
operator++
is neither a member function nor a friend,
and is therefore defined outside and below the
{curly
braces}
of the class definition in
date.h,
just as we did for the final definition of prefix
operator++.
operator++
function must create and return a new object of class
date.
The pedagogical examples create a new object by explicitly creating a
copy of the object they belong to.
The non-pedagogical example creates an object in an easier way,
simply by using pass-by-value
to create a copy of the object that was passed to it.
operator+,
the postfix
operator++
returns the new object it created.
Unfortunately, we must create and return a copy of this new object,
because the new object dies when the postfix
operator++
function returns.
To make sure that no one tries to change the new object,
the return value is a
const
object:
date d; //Okay to use the vale of the expression d++ cout << d++ << "\n"; //But not okay to try to change the value of the expressio d++ (d++) += 7;
operator++
is
operator+=
and prefix
operator++
change the value of an existing object.
Their return values are of type
date&.
operator+
and postfix
operator++
construct and return a new object.
Their return values are of type
const date.
operator++
calls prefix
operator++
to do part of its work.
operator+
and prefix
operator++
call
operator+=
to do part of their work.
date
equipped with all the operators we have overloaded so far.
Also add the four subtraction operators
-=,
-,
prefix
--,
and postfix
--,
corresponding to the four addition operators
+=,
+,
prefix
++,
and postfix
++.
A function that need to mention the private members of two (or more) objects of the same class should be a friend function of the class.
operator-.
operator-
we already have accepts an object and an
int.
It constructs and returns a new object that is “smaller”
than the original object
(at least, if the
int
is positive).
operator-
will accept two objects,
and will therefore be a friend.
It will return an
int
giving the distance between the two objects.
operator==
and
operator<
should also be friends.
The four other comparison operators
(operator!=,
operator<=,
operator>,
operator>=)
do not need to be member functions or friends,
because they can do their work by calling
operator==
and
operator<.
Why does C++ allow us to make our own definition of what
==
means?
“Close enough for government work.”
>>
already accepts an object of class
istream
(such as the object
cin)
as its left operand.
We will now let the operator accept an object of class
date
as its right operand.
The function
operator>>
has to be a friend for the same reason that the function
operator<<
had to be a friend.
The
operator<<
for class
date
had to perform five separate output operations:
int,
char,
int,
char,
int.
Similarly, the
operator>>
for class
date
has to perform five separate input operations:
int,
char,
int,
char,
int.
The two
chars
should be diagonal slashes.
If the
chars
are the wrong
chars,
or if the ints
are the wrong
ints,
we call
setstate
to inject
cin
with a dye marking it as unhealthy.
static_cast<int>()
operator.
grade
can hold one of 14 possible values:
F F+ D- D D+ C- C C+ B- B B+ A- A A+
Class
grade
already has a few operators.
Give it
all the operators we gave to class
date.
operator+ (object + int) operator+ (int + object) operator++ (prefix) operator++ (postfix) operator- (object - int) operator- (object - object) operator== operator< operator<= operator> operator>= operator!=
In the
for
loop in
main.C,
note that we are now able to write the
grade
object
a[i]
in a situation (after the +=)
where normally we would have to write an
int.
cin
(namely, class
istream)
has the following functions.
int i {0};
cout << "Please type an int (or control-d to exit): ";
cin >> i; //operator>>(cin, i);
if (cin) { //if (cin.operator bool()) {
cout << "The input was successful.\n";
}
if (!cin) { //if (cin.operator!()) {
cout << "The input was not successful.\n";
}
point
doesn’t need any
point.C
implementation file,
because all the member functions and friends of this class are inline,
and the class has no static data members.
Class
point
has a “copy constructor” and an
operator=
member function.
The two functions seem similar,
and they even take exactly the same argument
(const point& another).
But we can already see one difference between them:
operator=
ends with
return *this;,
just like
operator+=
and
operator-=.
This allows the following
y = x
to be used as part of a larger expression.
point x;
point y;
point z;
z = y = x;
Even if you never define the copy constructor and the
operator=
member function shown in
point.h,
the computer would behave as if you had defined them.
operator=?
"double
quoted"
strings in C++.
operator=.
An
operator=
usually has to do the work of the destructor,
followed by the work of the copy constructor,
checking if we really have two separate objects,
and it must return the object
*this.
(Digression:
see
string.C
for a string of
chars
in
"double
quotes".)
The
operator=
member function in the above
mystring.C
has three features that the copy constructor lacks:
if (this != &another) {
delete[] p;
return *this;
The rule of the Big Three:
If you have to write any of the following for your class,
you probably have to write all three of them:
operator= member functionmyrandom
does only one job: providing a random number.
In other words,
other than the constructor and destructor,
an object of this class has only one member function (rand)
that we will call.
In this case, we should have named the member function
operator().
for
loop in
main.C
is made out of familiar operators such as
>,
<<,
and
--.
Compare it with the
while
loop in
interesting.C.
interesting.C
by
fkhan67
timer.h
timer.C
because one of the member functions was too big to be inline
main.C
c++ timer.C main.C