irm chapter 6e 11
TRANSCRIPT
-
8/10/2019 IRM Chapter 6e 11
1/52
1Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
Chapter 11
Friends and Overloaded Operators
1. Solutions to and Remarks on Selected Programming Problems
1. Modify Money class.
No solution is provided for this exercise.
2. Implement constructors and overload >>,
-
8/10/2019 IRM Chapter 6e 11
2/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
2Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
int accessFirst();
int accessSecond();
// other members and friends
friend Pair operator+(const Pair&, const Pair&);
friend Pair operator*(const Pair&, int);
friend istream& operator>> (istream&, Pair&);
friend ostream& operator
-
8/10/2019 IRM Chapter 6e 11
3/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
3Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
x = y + z;
cout second.f;
ins >> ch; // discard comma ','
ins >> second.s;
ins >> ch; // discard final '('
return ins;
}
ostream& operator
-
8/10/2019 IRM Chapter 6e 11
4/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
4Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
outs
-
8/10/2019 IRM Chapter 6e 11
5/52
-
8/10/2019 IRM Chapter 6e 11
6/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
6Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
{
public:
Rational(int numerator, int denominator);
Rational(int numerator); // sets denominator to 1
Rational(); // sets numerator to 0, denominator to 1
friend Rational operator+(const Rational&,
const Rational&);
friend Rational operator-(const Rational&,
const Rational&);
friend Rational operator*(const Rational&,
const Rational&);
friend Rational operator/(const Rational&,const Rational&);
friend bool operator=(const Rational&,
const Rational&);
friend bool operator ==(const Rational&,
const Rational&);
friend ostream& operator (istream&,
Rational&);
private:
int n;int d;
};
void normalize(int &n, int &d);
#endif
//end file Rational.h
-
8/10/2019 IRM Chapter 6e 11
7/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
7Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
//file: ch11prb4cc
//Implementations of the members of class Rational.
//For Chapter 11 Problem 4
#include
#include
#include "rational.h"
using namespace std;
//private members of class Rational
// int n;
// int d;
Rational::Rational(int numer, int denom)
{
normalize(numer, denom);
n = numer;
d = denom;
}
//sets denominator to 1
Rational::Rational(int numer): n(numer), d(1)
// See the initializer appendix
{
//body deliberately empty
}
// sets numerator to 0, denominator to 1
Rational::Rational():n(0), d(1)
// see initializer appendix{
//body deliberately empty
}
Rational operator +(const Rational& left,
const Rational& right)
-
8/10/2019 IRM Chapter 6e 11
8/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
8Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
{
int numer = left.n * right.d + left.d * right.n;
int denom = left.d * right.d;
normalize(numer, denom);
Rational local(numer, denom);return local;
}
Rational operator -(const Rational& left,
const Rational& right)
{
int numer = left.n * right.d - left.d * right.n;
int denom = left.d * right.d;
normalize(numer, denom);Rational local (numer, denom);
return local;
}
Rational operator *(const Rational& left,
const Rational& right)
{
Rational product;
int numer = left.n * right.n;
int denom = left.d * right.d;
normalize(numer, denom);
product = Rational(numer, denom);
return product;
}
Rational operator/(const Rational& left,
const Rational& right)
{
Rational quotient;int numer = left.n * right.d;
int denom = left.d * right.n;
normalize(numer, denom);
quotient = Rational(numer, denom);
return quotient;
}
-
8/10/2019 IRM Chapter 6e 11
9/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
9Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
//precondition: all relational operators require d > 0
bool operator =(const Rational& left,
const Rational& right)
{
return left.n * right.d >= right.n * left.d;
}
bool operator==(const Rational& left,
const Rational& right)
{
return left.n * right.d == right.n * left.d;}
//NOTE:
//Doing input changes the input stream state. This seems
//obvious, but I have students who didn't realize this.
-
8/10/2019 IRM Chapter 6e 11
10/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
10Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
//This code, along with iostream library, goes into an
//infinite loop if you make istream a const reference. There
//are no error messages, only an infinite loop, involving
//the single parameter constructor. This can be quite
//disconcerting to the naive student.//
//Bottom line: The first param MUST NOT be const. The
//second one is written, so it cannot be const either.
istream& operator >>(istream& in_str, Rational& right)
{
char ch;
in_str >> right.n >> ch >> right.d;if (ch != '/') // properly done, we would set iostream
//state
{// to fail here in case of error.
cout
-
8/10/2019 IRM Chapter 6e 11
11/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
11Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
char ch;
out_str
-
8/10/2019 IRM Chapter 6e 11
12/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
12Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
// remove common factors:
int g = gcd(n, d);
n = n/g;
d = d/g;
//fix things so that if the fraction is 'negative'
//it is n that carries the sign. If both n and d are
//negative, each is made positive.
if(n > 0 && d < 0 || n < 0 && d < 0)
{
n = -n;
d = -d;
}// assert: d > 0
}
//end file ch11prb4.cc
//File: ch11prb4.tst.cc
//File: test program for Rational class
#include
#include "rational.h"
using namespace std;
int main()
{
cout
-
8/10/2019 IRM Chapter 6e 11
13/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
13Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
cin >> x;
cout
-
8/10/2019 IRM Chapter 6e 11
14/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
14Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
w = Rational(-21,9);
z = Rational(3,5);
cout
-
8/10/2019 IRM Chapter 6e 11
15/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
15Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
Rational a(1,1); a outputs as: 1/1
-8/3 * 1/1 = -8/3
Testing arithmetic and relational operator overloading
25/9 * 3/5 = 5/3
25/9 + 3/5 = 152/4525/9 - 3/5 = 98/45
25/9 / 3/5 = 125/27
25/9 < 3/5 = 0
25/9 < 25/9 = 0
25/9 25/9 = 025/9 >= 3/5 = 1
25/9 >= 25/9 = 1
-7/3 * 3/5 = -7/5
-7/3 + 3/5 = -26/15
-7/3 - 3/5 = -44/15
-7/3 / 3/5 = -35/9
-7/3 < 3/5 = 1
-7/3 < -7/3 = 0
-7/3 -7/3 = 0
-7/3 >= 3/5 = 0
-7/3 >= -7/3 = 1
6. Complex Numbers
Define an ADT for complex numbers. The problem specifies a form of a + i*b where a
and b are of type double, and i is the complex unit, square root of -1. Implement
operator overloading for ==, +, -< *, >>, and
-
8/10/2019 IRM Chapter 6e 11
16/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
16Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
understandable to the student. Even so, I acknowledge some overkill for the problem as
specified in the text.
I have used an external form different from this specification. The ISO/ANSI C++
Standard says that the complex inserter and extractor should read and write a complex
numbers of the form: re, (re), or (re, im), where re is the real part and im is the imaginary
part. This is the external form that the C++ compilers will required by the ISO Standard
for compliant compilers.
I am only allowing the external form (re, im). I check only the input format, and I do not
check for a good stream state at each read from the input stream. Robust software
requires checking the stream state at each fetch.
The student should not be expected to have a knowledge of the requirements of the ISO
C++ Standard. Before assigning this exercise, the instructor should provide the student
with information about the external form of a complex the C++ Standard expects.
Not coincidentally, the ISO Standard requires a fully implemented type
with overloaded operators, transcendental functions, a complex arrays including array
slices, as part of the Numerics library.
//file: complex.h
// Chapter 11, problem 5: Define an ADT for complex numbers.
#ifndef _COMPLEX_H
#define _COMPLEX_H
#include
#include
using namespace std;
class complex{
public:
complex (double r = 0, double i = 0): re (r), im (i) { }
double real () const { return re; }
-
8/10/2019 IRM Chapter 6e 11
17/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
17Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
double imag () const { return im; }
private:
double re, im;
friend double real (const complex&) ;friend double imag (const complex&) ;
friend complex operator + (const complex&, const
complex&);
friend complex operator - (const complex&,
const complex&);
friend complex operator * (const complex&,
const complex&);
friend complex operator / (const complex&,const complex&);
friend bool operator == (const complex&,
const complex&);
friend bool operator != (const complex&,
const complex&);
friend complex polar (double, double);
friend istream& operator>> (istream&, complex&);
friend ostream& operator
-
8/10/2019 IRM Chapter 6e 11
18/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
18Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
o
-
8/10/2019 IRM Chapter 6e 11
19/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
19Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
//now get the imaginary part
ins >> i;
//and get the close parenthesis
ins >> ch;
if(')' != ch)//complex number must have a ')' last,
//If not, complain and exit.
{
cout
-
8/10/2019 IRM Chapter 6e 11
20/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
20Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
return complex (real (x) - real (y), imag (x) - imag (y));
}
complex operator * (const complex& x, const complex& y)
{return complex (real (x) * real (y) - imag (x) * imag (y),
real (x) * imag (y) + imag (x) * real
(y));
}
complex operator / (const complex& x, double y)
{
return complex (real (x) / y, imag (x) / y);}
bool operator == (const complex& x, const complex& y)
{
return real (x) == real (y) && imag (x) == imag (y);
}
bool operator != (const complex& x, const complex& y)
{
return real (x) != real (y) || imag (x) != imag (y);
}
double abs (const complex& x)
{
return sqrt(norm(x));
}
complex conj (const complex& x)
{
return complex (real (x), -imag (x));
}
double norm (const complex& x)
-
8/10/2019 IRM Chapter 6e 11
21/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
21Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
{
return real (x) * real (x) + imag (x) * imag (x);
}
//Divide overloading: There is a possible bug here.//The usual tool for complex division, num/den =
//num*conj(den)*(1/(den * conj(den)), causes an infinite
//recursion.
//Exercise: How and why?
complex operator / (const complex& num, const complex& den)
{
return(num * conj(den) * (1/norm(den)));}
//file: tstcmplx.cpp
//To test complex.h and complex.cpp class, members and
//friends
#include "complex.h"
#include "cmath"
using namespace std;
//compile command: g++ testcomplex.cpp complex-io.cpp
int main()
{
// test constructors
complex x, y(3), z(-3.2, 2.1);
cout
-
8/10/2019 IRM Chapter 6e 11
22/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
22Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
-
8/10/2019 IRM Chapter 6e 11
23/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
23Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
cout
-
8/10/2019 IRM Chapter 6e 11
24/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
24Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
(1,1)
(2,3)
Here is the output from our input routine when given bad data.
x = (0, 0) y = (3, 0) z = (-3.2, 2.1)
testing members and support functions as well as output
operator:
complex number x = (3, -4)
real part: 3
real part from friend real(x): 3
imaginary part: -4
imaginary part from friend imag(x) : -4
norm: 25
We test complex arithmetic and output routines.
x = (3, -4) y = (1, -1) z = (-3.2, 2.1)
z = x + y = (4, -5)
z = x * y = (-1, -7)
z = x - y = (2, -3)z = x / y = (3.5, -0.5)
d: 2 x: (3, -4)
x+d: (5, -4)
x-d: (1, -4)
x*d: (6, -8)
x/d: (1.5, -2)
d+x: (5, -4)d-x: (-1, 4)
d*x: (6, -8)
d/x: (0.24, 0.32)
two/x: (0.24, 0.32)
Getting data from standard input:
-
8/10/2019 IRM Chapter 6e 11
25/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
25Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
data read is: x = (1, 1) y = (2, 3)
Messages from the input routine when given bad data.
The content of the file, bad-data1, is:
(1 2)The messages from the input routine with this file for data follow.
[...snip...]
Getting data from standard input:
Bad complex form: found 2, need comma for complex input;
A complex must be of the form (re, im)
The content of the file, bad-data2, is:
(1,2)
(1,2_
The messages from the input routine with this file for data follow.
[...snip...]
Getting data from standard input:
Bad complex form: found _, need )for complex input;
A complex must be of the form (re, im)
7. No Solution Provided
8. No Solution Provided
9. No Solution Provided
10. No Solution Provided
11. No Solution Provided
12.
// ****************************************************************//// Ch11Proj12.cpp
-
8/10/2019 IRM Chapter 6e 11
26/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
26Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
//// This program defines a class for storing a set of STL strings.// The + operator unions two sets and the * operator intersects// two sets.//// ****************************************************************
#include #include #include #include
using namespace std;
class StringSet{public:
StringSet();StringSet(const string initialStrings[], int arraysize);bool add(const string s);bool remove(const string s);void clear();int size();void output();friend StringSet operator *(const StringSet &set1, const
StringSet &set2);friend StringSet operator +(const StringSet &set1, const
StringSet &set2);private:
int search(const string s);vector data;
};
// ======================// StringSet::StringSet// Default Constructor// ======================StringSet::StringSet(){}
// ======================// StringSet::StringSet// This constructor initializes the string set to those// strings in the input array.// ======================StringSet::StringSet(const string initialStrings[], int arraysize){
int i;for (i=0; i < arraysize; i++){
data.push_back(initialStrings[i]);}
}
-
8/10/2019 IRM Chapter 6e 11
27/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
27Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
// ======================// StringSet::Output// This method simply outputs all strings to the console.// ======================void StringSet::output(){
int i;for (i=0; i < data.size(); i++){
cout
-
8/10/2019 IRM Chapter 6e 11
28/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
28Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
i = search(s);if (i>=0){
return false; // s already in the set}
data.push_back(s);return true;
}
// ======================// StringSet::remove// Removes an entry from the vector.// If the entry doesnt exist, then "false" is returned,// otherwise "true" is returned and the string is removed.// ======================bool StringSet::remove(const string s){
int i;
i = search(s);if (i>=0){
// To remove the string from the vector, we make a new// copy of the vector without the string, then copy that// back to the original vector.// Chapter 18 describes a better technique using the
"erase"// method and iterators.vector temp;for (int j=0; j
-
8/10/2019 IRM Chapter 6e 11
29/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
29Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
// ======================StringSet operator *(const StringSet &set1, const StringSet &set2){
StringSet temp;int i,j;
for (i=0; i
-
8/10/2019 IRM Chapter 6e 11
30/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
30Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
cout
-
8/10/2019 IRM Chapter 6e 11
31/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
31Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
using namespace std;
// ******************************* Begin StringSet Class
class StringSet{
public:StringSet();StringSet(const string initialStrings[], int arraysize);bool add(const string s);bool remove(const string s);void clear();int size();void output();friend StringSet operator *(const StringSet &set1, const
StringSet &set2);friend StringSet operator +(const StringSet &set1, const
StringSet &set2);private:
int search(const string s);vector data;
};
// ======================// StringSet::StringSet// Default Constructor// ======================StringSet::StringSet(){}
// ======================
// StringSet::StringSet// This constructor initializes the string set to those// strings in the input array.// ======================StringSet::StringSet(const string initialStrings[], int arraysize){
int i;for (i=0; i < arraysize; i++){
data.push_back(initialStrings[i]);}
}
// ======================// StringSet::Output// This method simply outputs all strings to the console.// ======================void StringSet::output(){
int i;for (i=0; i < data.size(); i++){
cout
-
8/10/2019 IRM Chapter 6e 11
32/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
32Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
}}
// ======================// StringSet::clear// Erases all entries in the stringset.
// ======================void StringSet::clear(){
data.clear(); // Erases all elements from the vector}
// ======================// StringSet::size// Number of entries in the stringset.// ======================int StringSet::size(){
return data.size();}
// ======================// StringSet::search// This private member function searches the vector for// the target string. If found, the index is returned,// otherwise -1 is returned.// ======================int StringSet::search(const string s){
int i;for (i=0; i < data.size(); i++){
if (data[i]==s) return i;
}return -1;
}
// ======================// StringSet::add// Adds a new entry to the vector.// If the entry already exists, then "false" is returned,// otherwise "true" is returned.// ======================bool StringSet::add(const string s){
int i;
i = search(s);if (i>=0){
return false; // s already in the set}data.push_back(s);return true;
}
-
8/10/2019 IRM Chapter 6e 11
33/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
33Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
// ======================// StringSet::remove// Removes an entry from the vector.// If the entry doesnt exist, then "false" is returned,// otherwise "true" is returned and the string is removed.// ======================
bool StringSet::remove(const string s){
int i;
i = search(s);if (i>=0){
// To remove the string from the vector, we make a new// copy of the vector without the string, then copy that// back to the original vector.// Chapter 18 describes a better technique using the
"erase"// method and iterators.vector temp;for (int j=0; j
-
8/10/2019 IRM Chapter 6e 11
34/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
34Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
if (set1.data[i]==set2.data[j]){
temp.add(set1.data[i]);}
}}
return temp;}
// ======================// StringSet::operator +// Unions the current StringSet and otherSet, and returns// a new StringSet that is the union of the two.// This code adds all the strings from the first set to temp,// then adds any words from the second set as well. The add// function will weed out any duplicates.// ======================StringSet operator +(const StringSet &set1, const StringSet &set2){
StringSet temp;int i;
// Add everything from set 1for (i=0; i
-
8/10/2019 IRM Chapter 6e 11
35/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
35Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
getline(cin,s);if (s != string("")){
setKeywords.add(s);}
} while (s != string(""));
}
// ************************// ReadFileKeywords:// Opens the specified file for reading and inputs its words// into the StringSet.// ************************void readFileKeywords(StringSet &setDocument, const char filename[]){
ifstream in_stream;string s;
// Open the filein_stream.open(filename);if (in_stream.fail()){
cout s;
setDocument.add(s);}in_stream.close();
}
// ======================// main function// ======================int main(){// Variable declarationsStringSet doc1;StringSet doc2;StringSet query;
readFileKeywords(doc1, "Ch11Proj13Doc1.txt");readFileKeywords(doc2, "Ch11Proj13Doc2.txt");cout
-
8/10/2019 IRM Chapter 6e 11
36/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
36Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
StringSet intersect2 = doc2 * query;
// Calculate similarity to eachdouble sim1 = intersect1.size() / (sqrt(doc1.size()) *sqrt(query.size()));cout
-
8/10/2019 IRM Chapter 6e 11
37/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
37Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
Here many of the tools necessary for defining abstract data types are presented. The
notion of friend, the constkeyword, operator overloading, user-defined casts, and
separate compilation are all important to the construction of Abstract Data types.
Namespaces are treated, since the standard libraries require them.
11.1 Friend Functions
This section starts by revisiting the class DayOfYear. Recall that few of the operations
(+, /, -, ==,
-
8/10/2019 IRM Chapter 6e 11
38/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
38Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
Consequently, the friend function is not called with member access operators, unless it is
a member of some other class. The text does not discuss this.
We emphasize the class grantsfriendship. A function cannot unilaterally seize friendship
of a class. The declaration must be made in the class definition. It is pointed out in the
text that friend status can result in increased efficiency by allowing bypassing access
functions that are otherwise necessary.
A function that is a friend of a class, unless it is a function member of another class, will
be defined outside the scope of any class, making the function global, that is, accessible
in any function definition.
Like any programming effort, there is a balance to be struck between use of friend
functions and use of accessor functions. If a function needs to writeto a private
member of a class, one can have an accessor return a reference to the private
member, but this makes the privatemember globally writeable. In this case, we
might as well make the variable public. (This is where you needa friend :).2
Example:
//File: Friend.cc
//To illustrate return by reference.
#include using namespace std;
class F
{
public:
F();
//various constructors
int& rw_accessor_i();friend int& rw_friend_accessor_i(F& w);
int read_accessor_i();
private:
2The symbol :)is called a smiley. This was originally inserted into email to represent intent tobe amusing. There are many, many of these. See Smileys, David Sanderson, OReilly, 1993.
-
8/10/2019 IRM Chapter 6e 11
39/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
39Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
int i;
};
F::F() { i = 10; } //we could have written F::F():i(10) {}
int F::read_accessor_i(){ return i; }
int& F::rw_accessor_i()
{
return i; // not &i, which is the address of i.
}
The argument in the following function mustbe pass-by-reference otherwise only the
local variable xis changed when the variable that is returned is assigned, and the caller's
argument is not changed. This is a classic error. There must be a chain of references from
the returned value to the caller's argument.
int& rw_friend_accessor_i(F& x)
{
return x.i; //
}
int main()
{
F x;
cout
-
8/10/2019 IRM Chapter 6e 11
40/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
40Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
-
8/10/2019 IRM Chapter 6e 11
41/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
41Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
This suggests that the error is in the input or early in the output routines, since
my_amountis set by constructor. The value reported formy_amountis wrong, as
well as a ridiculous result for your_amount.
Placing output statements in Money::input determined that this routine was working
correctly. As soon as I looked at the output routine the lack of an= sign in the second
line jumped out at me. The errors in output for my_amount and your_amountare
caused by not setting positive_cents in that routine.
The other error was leaving out the last two lines of Money::input(istream&).
The program worked fine until tested with negative values, which were accepted, and
recorded as positive entries. These seem like trivial errors, but my students make errors
without having any idea about what the possibilities are, nor how to test to find the errors,
let alone how to do efficient testing.
A debugger can be a great help but it is not a panacea. Frequently it is faster to insert
output statements at places in the code that are suggested by the errors produced. Under
any circumstances, whether a debugger is used or output statements are added, planning
is necessary.
Again, I point out the need for the student to create her own exercises like those in
Chapter 1 of the text that help students see what error messages are issued for particular
questions about syntax.
Many errors are more subtle. Fixing the typo fixed the routine, until I tried it for negative
money amounts, as noted above.
The const Parameter Modifier
Remember these three things about usage of the constkeyword. One: Use of the
keyword constis a promise to the compiler that you wont write code that changes
something. Two: This use is a request that the compiler enforce these promises. Three:
The use of constis difficult or impossible to retrofit. If you write code without const
correctness, that code almost certainly will have to be rewritten from the ground up to get
the code right.
The declaration
-
8/10/2019 IRM Chapter 6e 11
42/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
42Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
const int x = 3;
is a promise to the compiler that you wont write anything that has the potential to change
x,such as using x on the left of an assignment statement or as an argument to a non-
const reference parameter. A constmember function promises not to change any classdata using that function. A use of const in a class object declaration promises that you
wont call any function with the potential to change that objects data members. As
mentioned, the compiler tries to enforce these promises.
The text points out that use of the constkeyword requires consistency. If you declare a
constparameter for a function member declaration in a class, you mustuse the const
keyword in your definition of that function member. If you use a non-constobject for
an argument, and do not declare the function with a constparameter, you should get anerror or a warning from your compiler. If you fail to declare a member function to be
const, then call this member on behalf of a constobject of this class, as below, you
should get an error. The reason is in C++ the compilers encode all the information about
a function: name of the function, the sequence of types in the argument list, including
const qualifiers, and for member functions of a class, any const qualifiers that follow the
declaration and uses this as the function name. If the constqualifier is in the definition
but not in the class declaration, as far as the compiler is concerned, they are different
functions, and you get an error.
It is worth noting that in the following example, the Borland compiler is more forgiving
of the const errors than the GNU compiler. The point is that each compiler has things it is
fussy about. Know your compiler.
//File: test.const.cc
//to test attempt use of non-const arg for nonconst
//reference parameter. and to apply a nonconst member
//to a const object
#include
using namespace std;
class C
{
-
8/10/2019 IRM Chapter 6e 11
43/52
-
8/10/2019 IRM Chapter 6e 11
44/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
44Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
Compilation finished at Sun Dec 31 16:38:51
g++ -c test.const.cpp
In function 'int main()':
29: passing 'const C' as 'this' argument of 'voidC::output()' discards qualifiers
30: conversion from 'const int' to 'int &' discards
qualifiers
25: in passing argument 1 of 't(int &)'
Compilation exited abnormally with code 1 at Sun Dec 31
16:37:54
Overloading Operators
Suppose the compiler seesx andy in the context
x op y
where one of x ory is an object of class Some_Class. For the sake of definiteness,
suppose it isx that is of classSome_Class. Further, suppose 'op' is one of the
many C++ operators capable of being overloaded. The compiler then looks for a
function:
return_type operator op(Some_Class x, type_name y);
or for a member function
return_type Some_Class::operator op(type_name y);
to which the compiler generates a call.
For example, consider the infix expression
x + y
where for the variablesx andy have been defined to have the inttype. If the
operatorop were overloaded as a standalone function, the infix expression is translated
into the direct call to the operator function,
operator+ (x, y);
-
8/10/2019 IRM Chapter 6e 11
45/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
45Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
If the operator op were overloaded as a standalone function, the infix expression is
translated into this direct call to the operator function,
x.operator+(y);
The programmer can actually write direct calls to the operator functions, but there is no
good reason to do so other than to verify that this is possible. Nevertheless, my students
want to call the operator functions directly instead of the infix operators. I found it
necessary to spend some time emphasizing that the compiler does that for them.
Some Rules
1. Precedence and arity (the number of arguments) of the operator cannot be changed by
overloading. For example, a binary/ cannot be made to be a unary operator.
2. Operator functions for=, ->, [] and () must be non-static members of the
class to which they apply. (Overloading of the operators =, [] and-> is discussed
later in the text.)
The student must know and understand the rules listed on page 471 of the text.
Friends Vs Member overloading (for the instructor)
Please note that the text does not discuss overloading operators as members until Chapter
11.
There is a compelling argument in favor of overloading operators using friends rather
than overloading as members. Professor Savitch pointed out to me that he did not put
both in the text at this point because presumably the students only know about the friend
overloading method. It is worth pointing out to the instructor that if both operands are
arguments, then C++ will do automatic type conversion of either argument to the class
type from simple types such as int (provided you have supplied an appropriate
constructor). This allows you to use 2 as a Rational or an amount of money in an
expression such as
object + 2
or
2 + object
-
8/10/2019 IRM Chapter 6e 11
46/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
46Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
which are converted to
operator+(object, 2);
or
operator+(2, object);
where the non class type arguments will be converted to an object using the constructor
having anintargument. However, if operator+is a member, then the first argument
must always be an object,
as in:
object + 2
and expressions such as
2 + object
are always illegal. This is the reason for presenting the friend rather than member
operator overloading first.
More detail on operator overloading (for the instructor)
The decision on whether to write an overloading operator function as a stand-alone
function (most likely a friend of the class) or to write the operator function as a memberdepends on several things. Is the operator expected to behave symmetrically between the
arguments? If so, the operator should be a standalone function (and probably a friend of
the class). If the asymmetry is desired or is no problem, then a member operator function
may be used.
Here is an example, stripped of all details except the minimum to illustrate the language
behavior. This code illustrates the essential asymmetry of operators overloaded as
members.
//File: overload1.cc
//to test behavior of member operator overloading.
//What conversions and when the conversions are made.
#include
-
8/10/2019 IRM Chapter 6e 11
47/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
47Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
using namespace std;
class F
{
public:F(){};
void operator +(Fx);
F(int);
operator int ();
};
F::F(){} //does nothing
F::F(int)
{
cout
-
8/10/2019 IRM Chapter 6e 11
48/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
48Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
F x;
int i = 2;
cout
-
8/10/2019 IRM Chapter 6e 11
49/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
49Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
using namespace std;
class F
{
public:friend F operator +(F u, F v);
F(int q);
operator int ();
private:
int p;
};
F::F(int q){
p = q;
cout
-
8/10/2019 IRM Chapter 6e 11
50/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
50Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
int i = 2;
cout
-
8/10/2019 IRM Chapter 6e 11
51/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
51Copyright 2007 Pearson Education, Inc. Publishing as Pearson Addison-Wesley
If we are the class author, we can add a member overloading
operator
-
8/10/2019 IRM Chapter 6e 11
52/52
Savitch Instructors Resource GuideProblem Solving w/ C++, 6e Chapter 11
The difference in coding amounts to replacing the return type with void, and removing
the returnstatement from the function. The sole advantage is not having to return the
stream.
// returns istream&:istream& operator >> (istream& ins, Money& amount)
{
//all the necessary code to fetch the amount
//from the istream and do some format checking
//are in Display 11.8 in the text.
return ins;
}
void operator >> (istream& ins, Money& amount)
{
//all the necessary code to fetch the amount
//from the istream and do some format checking
//are in Display 11.8 in the text.
//no return statement
}
Similar arrangements work for overloading operator