You are on page 1of 28

COS1512/202/2/2011

SCHOOL OF COMPUTING

COS1512

Introduction to Programming 2

Due to regulatory requirements imposed by the Department of National Education the following
apply:

To be considered for examination admission in COS1512, a student must meet the following
requirement:

Submit assignment 1 or assignment 2 BEFORE 22 August 2011.

Tutorial Letter 202:


Solution to Assignment 2
2

Content
1. Introduction ......................................................................................................................................................2
2. Tutorial matter distributed to date ....................................................................................................................2
3. Allocation of marks ..........................................................................................................................................3
4. Solution to Assignment.....................................................................................................................................4

1. Introduction
The purpose of this tutorial letter is to supply the solution for Assignment 2, and to indicate how you should interpret
the results you obtained for this assignment. This assignment covers the work discussed in Chapters 10, 11 and 12 of
the study guide (Appendix F in Tutorial Letter 101), as well as the relevant sections in Chapters 10, 11 and 12, and
Appendices 7 and 8 of Savitch. Note that you should have included the input and output of all programs you were
required to write.

The assessment and feedback given on your assignment, serve as an indication of your mastering of the study
material.
If you received a good mark, you can be confident that you are on the right track. If you did not receive a good
mark, it is an indication that you need to revise your study method for COS1512.

2. Tutorial matter distributed to date


CD Prescribed software
COS1512/101/3/2011 First tutorial letter: General information, study programme, exam admission and
assignments
COS1512/102/2/2011 Invitation to Workshop
COS1512/103/2/2011 Solution to Workshop Exercises
COS1512/201/2/2011 Solution to Assignment 1
COS1512/202/2/2011 This letter: Solution to Assignment 2

If you have not received all of the above-mentioned tutorial matter, please download it from myUnisa at
https://my.unisa.ac.za.
3 COS1512/202/2/2011

3. Allocation of marks
When we mark assignments, we comment on your answers. Many students make the same mistakes and
consequently we discuss general problems in the tutorial letters. It is, therefore, important to work through the
tutorial letters and to make sure you understand our solutions and where you went wrong.

The maximum number of marks you could obtain for Assignment 2 is 50. This is converted to a percentage.
If you for instance obtained 25 marks for Assignment 2, you received 50% for Assignment 2. This percentage
in turn contributes a weight of 80% to the year mark, as can be seen in the summary of the weights allocated to
the assignments for COS1512 below.

Assignment number Weight


1 20
2 80
3 0

Questions 3 and 6 has not been marked. However, 5 marks are awarded if you attempted this question (note that this
is not the way in which questions will be marked in the examination!). We include complete solutions for all
questions.

The marks you received for questions 1 and 5 were determined on the following basis:
Question not done 0/5
Question attempted, but the program does not work at all 2/5
A good attempt, but there are a few problems with your answer 4/5
The program works correctly and produces the correct output 5/5

The marks you received for question 2 were determined on the following basis:
Question not done 0/15
Each correct response to questions (a,c,d and i) = 2 marks 8/15
Each correct response to questions (b,e,f and g) = 1 mark 4/15
Question (h) = 3 marks 3/15

The marks you received for question 4 was determined on the following basis:
Question not done 0/15
Question attempted, but the program does not work at all 6/15
A good attempt, but there are a few problems with your answer 12/15
The program works correctly and produces the correct output 15/15

In other words, you can obtain a maximum of 5 marks for questions 1 and 5, and a maximum of 15 marks for
questions 2 and 4.

Note that not all mistakes are corrected – but we will provide informative comments.

If you did not include the program output for questions 1 and 5, it means there are “a few problems with your
answer” and the maximum you can get is then 4/5. If you did not include the program output for question 4, it means
there are “a few problems with your answer” and the maximum you can get is then 12/15.

We did not award any marks to assignments submitted more than four weeks after the due date. However, we still
provided informative comments.
4

4. Solution to Assignment
Question 1 [max of 5 marks]

Discussion:
For this question, you had to convert the struct Module into a class. There is essentially only a slight difference
between a struct and a class. A class is the same as a struct (i.e. a struct may also contain both
member variables and member functions just like a class, even though the examples in Savitch do not show that)
except that, by default, all members are inaccessible to the general user of the class. This means that all members of a
struct are by default public, and all members of a class are by default private. Therefore, we have to
specify that the member functions are public. (As an exercise, omit the public keyword from the class and
recompile it.) While there are situations where a struct is more suitable, as a rule, you should use classes rather
than structs. In general, it is preferable to use classes, as classes offer better protection.

An object encapsulates or combines data and operations on that data into a single unit. In C++, the mechanism that
allows you to combine data and the operations on that data in a single unit is called a class.

A class can be seen as a user-defined data type. We use a class to declare or instantiate an object. When an object
of a specific class is instantiated, the constructor for the class is called by default. The purpose of the constructor is to
initialise the member variables of the object automatically. This means that a constructor should not include
instructions to obtain values for the member variables (cin statements). It also means that the member variables
should not be re-declared inside the constructor, since these variables will then be local to the function, and will
prevent the constructor function from accessing the member variables to initialise them. Study the constructor for
class Module as shown below to see how these concepts are implemented:
//implementation
Module::Module()//constructor
{
moduleName = " ";
moduleCode = "0000000";
lecturer = " ";
nrStudents = 0;
}

As moduleName, moduleCode, lecturer, and nrStudents are private member variables (see page 549
of Savitch 6th edition/ page 581 of Savitch 7th edition) of class Module, they cannot be accessed directly in the
main() function. As a result, public member functions getModName(), getModCode(), getLecturer()
and getNrStdts() are used to access these member variables in order to determine their values. These functions
are known as accessor functions, while setModName(), setModCode(), setLecturer() and
setNrStdts()are mutator functions. (Study pages 553 – 554 of Savitch, 6th edition/ pages 585 -586 of Savitch 7th
edition).

Note the prototypes for member functions:


string getModName() const;
string getModCode() const;
string getLecturer() const;
int getNrStdts() const;

These member function are accessors - hence the const keyword at the end of the function definition. Note that a
member function that does not have the const keyword at the end of it may possibly mutate (change or modify) the
state of the object.

Note that the purpose of an accessor function (a function whose name starts with get, and sometimes called a
5 COS1512/202/2/2011

‘get function’) is not to obtain an input value for the member variable from a user, BUT to return the current
value of the member variable. Accessor functions need to indicate a return type corresponding to the member
variable for which it returns a value. An accessor function has no parameters. Since an accessor function is a
member function of the class, it refers directly to the member variable which value it should return in the body of
the function, i.e. there is no need to declare (and return) a local variable inside an accessor function. In fact, if
you do declare a local variable inside an accessor function, and return the value of the local variable, it will NOT
return the current value of the member variable!

Study the accessor function getModName() to see how these concepts are implemented:
//Accessors to retrieve (get) data from each of member variables
string Module::getModName()const
{
return moduleName;
}

Mutator functions (functions whose names start with set, and sometimes called ‘set functions’) are used to change or
modify member variables of an object. The parameter of the mutator function typically indicates the value according
to which the member variable should be changed. For example, the mutator function setModName()below
modifies member variable moduleName to n:
void Module::setModName(string n)
{
moduleName = n;
}

Program listing:
#include <iostream>
#include <string>
using namespace std;

class Module
{
public:
Module();
Module(string n, string c, string l, int nr);
void setModName(string n);
void setModCode(string c);
void setLecturer(string l);
void setNrStdts(int n);
string getModName()const;
string getModCode()const;
string getLecturer()const;
int getNrStdts()const;
private:
string moduleName;
string moduleCode;
string lecturer;
int nrStudents;
};

//implementation
Module::Module() //default constructor
{
moduleName = " ";
moduleCode = "0000000";
lecturer = " ";
nrStudents = 0;
}
6

Module::Module(string n, string c, string l, int nr) //overloaded


//constructor
{
moduleName = n;
moduleCode = c;
lecturer = l;
nrStudents = nr;
}

//Mutators to change (set) the value of each member variable

void Module::setModName(string n)
{
moduleName = n;
}

void Module::setModCode(string c)
{
moduleCode = c;
}

void Module::setLecturer(string l)
{
lecturer = l;
}

void Module::setNrStdts(int n)
{
nrStudents = n;
}

//Accessors to retrieve (get) data from each of member variables

string Module::getModName()const
{
return moduleName;
}

string Module::getModCode()const
{
return moduleCode;
}

string Module::getLecturer()const
{
return lecturer;
}

int Module::getNrStdts()const
{
return nrStudents;
}

//main application
int main()
{
string mName;
string mCode;
string lect;
7 COS1512/202/2/2011

int nrStds;

cout << "Please enter the module information:" << endl;


cout << "Module name: ";
getline(cin, mName, '\n');
cout << "Module code: ";
cin >> mCode;
cout << "Lecturer: ";
cin.get();//to extract '\n’ left over from previous cin >>
//otherwise we cannot input lecturer
getline(cin, lect, '\n');
cout << "Number of students for this module: ";
cin >> nrStds;
Module myModule(mName, mCode,lect,nrStds);
cout << endl << "Module information: " << endl;
cout << myModule.getModCode() << endl;
cout << myModule.getModName() << endl;
cout << myModule.getLecturer() << endl;
cout << myModule.getNrStdts() << endl;
return 0;
}

Input and Output:


Please enter the module information:
Module name: Introduction to Programming I
Module code: COS1512
Lecturer: Mrs Schoeman
Number of students for this module: 543

Module information:
COS1512
Introduction to Programming II
Mrs Schoeman
543
Press any key to continue . . .

Question 2 [max of 15 marks]


a) What is the purpose of the keywords public and private in the class declaration?

Member variables and member functions declared following a private label are accessible only to other
member functions of the class. Data members and member functions following a public label are accessible to
functions that are not members of the class (client functions).

b) What is the purpose of a constructor?

A constructor is automatically invoked when an object is defined. The constructor can initialise some or all of
the object’s data members to appropriate values.
(c) Give implementations of the default constructor and the second constructor, as well as the destructor.
Money::Money() //default constructor
{
rands = 0;
cents = 0;
}
Money::Money(int r, int c) //constructor with default parameters
8

{
rands = r;
cents = c;
}

Money::~Money() //destructor
{
}

d) Implement the Plus() member function. The Plus() member function should add a Money object to the
existing Money object, and return the sum as a Money object.
Money Money::Plus(Money m)
{
Money temp;
int c;
c = (cents + m.cents) + (100 * (rands + m.rands ));
temp.rands = c / 100;
temp.cents = c % 100;
return temp;
}

e) Implement the overloaded operator+ that adds a Money object to the existing Money object, and returns the
sum as a Money object.

Money Money::operator + (Money & m)


{
Money temp;
int c;
c = (cents + m.cents) + (100 * (rands + m.rands ));
temp.rands = c / 100;
temp.cents = c % 100;
return temp;
}
f) The member function greaterThan() is used to compare two Money objects with each other. Give an
implementation for this member function.

bool Money::GreaterThan(const Money m) const


{
return ((100*rands + cents) > (100*m.theRands() +
m.theCents()));
}

Discussion:
Note that since the member function greaterThan() should not change any of the two Money objects
that it compares, we use const modifier on both the function itself as well as its parameter.

g) Overload the stream insertion operator as a friend function. It should use the member functions the
theRands and the theCents to write the value of the Money object to the given output stream.

ostream &operator<<(ostream &sout, const Money &m)


{
if (m.theCents() < 10)
sout << "R" << m.theRands() << ".0" << m.theCents() ;
else
sout << "R" << m.theRands() << "." << m.theCents() ;
return sout;
}
9 COS1512/202/2/2011

h) The statement
if (m1 > m2)
cout << m2 << " is greater than " << m1 << endl;
else
cout << m2 << " is less than " << m1 << endl;
displays a message to indicate which value is bigger. Give three different implementations for the overloaded
operator > to accomplish this:
• using the member function greaterThan()
• implementing the overloaded operator > as a friend function
• implementing the overloaded operator > as a member function. Hint: See chapter 11 in the study guide,
Appendix F.

METHOD 1: Using the member function greaterThan() in other words, defining operator> as a non-friend,
non-member function:

We add on the prototype to the interface file, as shown in bold.


class Money
{
public:
friend ostream &operator<<(ostream &sout, const Money &r);
Money(); // default constructor
Money(int r, int c); // constructor
~Money(); // destructor
int theRands() const;
int theCents() const;
Money Plus(Money m);
Money operator+ (Money & m);
bool GreaterThan(Money m);
bool operator > (const Money m) const;
private:
int rands;
int cents;
};
The implementation:
bool Money:: operator > (const Money m)const
{
return GreaterThan(m);
}

This implementation of the overloaded operator > as well as its parameter have to use the modifier const since the
function GreaterThan() uses it. See pages 658 -661 in Savitch 7th edition for more on the consistent use of the
const modifier.

NB: There is actually no need to make operator> a friend function, as greaterThan()is a public member and
does the work for it. (Refer Tutorial Letter 104 [Solutions to the Workshop] for explanations on overloading the >
operator)

METHOD 2: Implementing overloaded operator> as a friend function


We insert the statement in bold into the class interface.

class Money
10

{
public:
friend ostream &operator<<(ostream &sout, const Money &r);
friend bool operator > (const Money m1, const Money m2);
Money(); // default constructor
Money(int r, int c); // constructor
~Money(); // destructor
int theRands() const;
int theCents() const;
Money Plus(Money m);
Money operator+ (Money & m);
bool GreaterThan(Money m);
private:
int rands;
int cents;
};

The implementation:
bool operator > (const Money m1, const Money m2)
{
return ((100*m1.rands + m1.cents) > (100*m2.rands +
m2.cents));
}
We could have left the implementation the same as before. However for illustrative purposes - we show that we now
have access to the private member variables of Money and hence we can manipulate them directly without using the
GreaterThan() member function. Once again, we use the const modifier to prevent any changes to the
parameters.

METHOD 3: Implementing the overloaded operator> as a member function.

We insert the statement in bold into the interface:

class Money
{
public:
friend ostream &operator<<(ostream &sout, const Money &r);
Money(); // default constructor
Money(int r, int c); // constructor
~Money(); // destructor
int theRands() const;
int theCents() const;
Money Plus(Money m);
Money operator+ (Money & m);
bool operator > (const Money m) const;
private:
int rands;
int cents;
};

The implementation:
bool Money:: operator > (const Money m) const
{
return ((100*rands + cents) > (100*m.theRands() +
m.theCents()));;
}

Again, we use the const modifier to prevent any changes to the parameter or calling object.
11 COS1512/202/2/2011

The implementation of member function operator>() has a type qualifier (see page 543, Savitch for a definition). In
other words we had to insert Money:: in the implementation. However the implementation of operator>() in
METHOD 2 has no type qualifier, as the operator is not a member function but rather a friend function.

Friend functions of a class are actually non-member functions of the class that have access to the private members of
that class (see pages 600 – 618 of Savitch). Some experts believe that friend functions should be generally avoided as
they can manipulate the underlying data representation of an object. But there are valid reasons towards its use in
terms of operator overloading. Operators may be overloaded as member functions, or as non-member non-friend
functions or as friend functions. See appendix 8, on page 993 of Savitch for a complete discussion as to why defining
operators as friend functions is preferable. As defining operators as friend functions are preferable we present our
final version of the program accordingly (see (i)).

i) Run your program three times: each time with a different version of the overloaded operator >; comment the
other two versions out during each run.
The output is shown below the program listing.

Full program Listing:

#include <iostream>
using namespace std;
class Money
{
public:
friend ostream &operator<<(ostream &sout, const Money &r);
friend bool operator > (const Money m1, const Money m2);
Money(); // default constructor
Money(int r, int c); // constructor
~Money(); // destructor
int theRands() const;
int theCents() const;
Money Plus(Money m);
Money operator+ (Money & m);
bool GreaterThan(const Money m) const;
private:
int rands;
int cents;
};
//implementation
Money::Money() //default constructor
{
rands = 0;
cents = 0;
}
Money::Money(int r, int c) //constructor with default parameters
{
rands = r;
cents = c;
}

Money::~Money() //destructor
{
}

int Money::theRands() const


{
return rands;
}
12

int Money::theCents() const


{
return cents;
}

Money Money::Plus(Money m)
{
Money temp;
int c;
c = (cents + m.cents) + (100 * (rands + m.rands ));
temp.rands = c / 100;
temp.cents = c % 100;
return temp;
}

Money Money::operator + (Money & m)


{
Money temp;
int c;
c = (cents + m.cents) + (100 * (rands + m.rands ));
temp.rands = c / 100;
temp.cents = c % 100;
return temp;
}

bool Money::GreaterThan(const Money m) const


{
return ((100*rands + cents) > (100*m.theRands() + m.theCents()));
}

bool operator > (const Money m1, const Money m2)


{
return ((100*m1.rands + m1.cents) > (100*m2.rands + m2.cents));
}

ostream &operator<<(ostream &sout, const Money &m)


{
if (m.theCents() < 10)
sout << "R" << m.theRands() << ".0" << m.theCents() ;
else
sout << "R" << m.theRands() << "." << m.theCents() ;
return sout;
}
//test class
int main()
{
Money m1;
Money m2(15,90);
Money m3(5,15);
m1 = m2.Plus(m3);
cout << m1 << " + " << m2 << " gives " << m1.Plus(m2) << endl;
m1 = m2 + m3;
cout << m2 << " + " << m3 << " gives " << m1 << endl;
if (m2.GreaterThan(m1))
cout << m2 << " is greater than " << m1 << endl;
else
cout << m2 << " is less than " << m1 << endl;
return 0;
}
13 COS1512/202/2/2011

Output:
R21.05 + R15.90 gives R36.95
R15.90 + R5.15 gives R21.05
R15.90 is less than R21.05
Press any key to continue . . .

Question 3 [This question has not been marked. A max of 5 marks if you attempted
this question]

Discussion:
For this question, you had to write a C++ program to test the Money class implemented in question 2 in this
assignment. You also had to convert the Money class from question 2 into an ADT, so that separate files are used for
the interface and implementation. See section 10.3, page 573 – 582 of Savitch 6th edition / page 605-614 of Savitch
7th edition for more on ADT’s and section 12.1, page 683 – 693 of Savitch 6th edition / page 726 – 741 of Savitch 7th
edition for more on separate compilation.

C++ has facilities for dividing a program into parts that are kept in separate files, compiled separately, and then
linked together when the program is run. The header (.h) files are effectively the interfaces of the different classes,
and the .cpp files contain the implementations.

For this exercise, you should have created three files:


Money.h
Money.cpp
TestMoney.cpp

Tips for separate compilation with multiple files in Devcpp:


• Only the .cpp files should be ‘added’ to the project.
• All files must be in the same directory or folder as the project file (the .dev file).
• The .cpp files must contain the preprocessor directive to include the .h files.
e.g. #include " Money.h"
Reference: Tutorial letter 101 Appendix A section 4 for more information.

Changes to the code of question 2 to allow separate compilation are indicated in bold. Note that all the files
(Money.h, Money.cpp and TestMoney.cpp) must be in the same folder.

Program listing:
//Money.h Class definition / interface for class Money:
//class Money in Money.h
#ifndef Money_h
#define Money_h
#include <iostream>
using namespace std;
class Money
{
public:
friend ostream &operator<<(ostream &sout, const Money &r);
friend bool operator > (const Money m1, const Money m2);
Money(); // default constructor
Money(int r, int c); // constructor
~Money(); // destructor
int theRands() const;
int theCents() const;
14

Money Plus(Money m);


Money operator+ (Money & m);
bool GreaterThan(const Money m)const;
private:
int rands;
int cents;
};

#endif

//Money.cpp: Implementation file for the Money ADT

#include <iomanip>
#include <iostream>
#include "Money.h"
using namespace std;
//implementation
Money::Money() //default constructor
{
rands = 0;
cents = 0;
}
Money::Money(int r, int c) //constructor with default parameters
{
rands = r;
cents = c;
}

Money::~Money() //destructor
{
}

int Money::theRands() const


{
return rands;
}

int Money::theCents() const


{
return cents;
}

Money Money::Plus(Money m)
{
Money temp;
int c;
c = (cents + m.cents) + (100 * (rands + m.rands ));
temp.rands = c / 100;
temp.cents = c % 100;
return temp;
}

Money Money::operator + (Money & m)


{
Money temp;
int c;
c = (cents + m.cents) + (100 * (rands + m.rands ));
temp.rands = c / 100;
15 COS1512/202/2/2011

temp.cents = c % 100;
return temp;
}

bool Money::GreaterThan(const Money m) const


{
return ((100*rands + cents) > (100*m.theRands() + m.theCents()));
}

bool operator > (const Money m1, const Money m2) //friend function
{
return ((100*m1.rands + m1.cents) > (100*m2.rands + m2.cents));
}

ostream &operator<<(ostream &sout, const Money &m)


{
if (m.theCents() < 10)
sout << "R" << m.theRands() << ".0" << m.theCents() ;
else
sout << "R" << m.theRands() << "." << m.theCents() ;
return sout;
}

// TestMoney.cpp Application file using class Money:


#include <iostream>
#include <string>
#include "money.h"

using namespace std;

int main()
{
Money m1;
Money m2(15,90);
Money m3(5,15);
m1 = m2.Plus(m3);
cout << m1 << " + " << m2 << " gives " << m1.Plus(m2) << endl;
m1 = m2 + m3;
cout << m2 << " + " << m3 << " gives " << m1 << endl;
if (m2.GreaterThan(m1))
cout << m2 << " is greater than " << m1 << endl;
else
cout << m2 << " is less than " << m1 << endl;
return 0;
}
Output:
R21.05 + R15.90 gives R36.95
R15.90 + R5.15 gives R21.05
R15.90 is less than R21.05
Press any key to continue . . .

Question 4 [max of 15 marks]

Discussion:
For this question, you had to define a class Player as an ADT with member variables name, team, level and
16

points. The class contains


• a default constructor,
• an overloaded constructor,
• a destructor,
• accessor and mutator functions for each of the member variables,
• a void member function reset();
• a void member function requestHint();
• and overloaded friend functions for the operators ==, >, ++ and -- as well as for the stream extraction
operator >> and the stream insertion operator <<.

Consider operators ==, >, ++ and -- overloaded as friend functions of the class Player:
friend Player operator++(Player &P);
friend Player operator--(Player &P);
friend bool operator>(const Player &player1, const Player
&player2);
friend bool operator==(const Player &player1, const Player
&player2);

Note, the const keyword is used to guarantee that the operator> and operator== functions will not modify
the Player objects. When we compare two Player objects with == or >, we do not want to change or modify
the objects we compare. The same situation holds if we would define + and – operators for class Player, i.e.
should we wish to add (+) or subtract (-) two Player objects, we would not want the objects that are added or
subtracted to change. A friend function may manipulate the underlying structure of the class but the const
keyword ensures that these manipulations do not modify the object in any possible way. We cannot place a const
at the end of each prototype as the function is not a member function.

The relational friend functions == and > return boolean values. Operator== returns true when the team
member variables of the two players are the same. Operator> returns true when the points member variable
of player1 is bigger than that of player2.

The prefix operator++ is a unary operator, which means that it takes only one operand, in contrast to binary
operators such as + or – which use two operands. Therefore, when overloading the prefix operator++ as a friend
function, only one parameter is specified, which represents the object that we want to increment:
friend Player operator++(Player &P);
Since the object will be modified in the friend function, it must be a reference parameter. In this implementation
of the prefix operator++, we increment the points member variable of the object, and also the level member
variable for every 100 points:
Player operator++(Player &P)
{
++P.points;
if (P.points % 100 == 0)
P.level++;
return P;
}
See also the discussion on Question 2(h) in this tutorial letter as well as the discussion following Question 4 in
Tutorial letter 103 on overloading the prefix operator.

In the same way we overload the operator-— to deduct 10 points when the user requests a hint, and adapt the
level if necessary:
Player operator--(Player &P)
{
P.points = P.points - 10;
if (P.points / 100 < P.level)
--P.level;
17 COS1512/202/2/2011

return P;
}

Note the difference between the overloaded friend functions for the stream extraction operator >> and the stream
insertion operator <<:
friend istream & operator>>(istream & ins, Player & P);
friend ostream & operator<<(ostream & out, const Player & P);

The overloaded stream insertion operator << uses the const keyword to ensure that the object which is sent to the
output stream will not be modified. In the case of the overloaded stream extraction operator >>, the object retrieved
from the input stream, must change. The overloaded stream insertion operator << modifies the output stream and the
overloaded stream extraction operator >> modifies the input stream, therefore both the ostream and the
istream must be reference parameters.

Also, note that in the implementation of the overloaded operator >> we do not use cout statements to tell the
user to type in input, or in what format the input should be. The purpose of overloading the operator >> is to allow us
to use the operator >> to read in (extract) an object in the same way we would use it to read in or extract an ordinary
variable. Consider the implementation of the overloaded >>:
istream & operator>>(istream & ins, Player & P)
{
ins >> P.name;
ins >> P.team;
ins >> P.points;
ins >> P.level;
return ins;
}

and the way it is used in the application:


Player player3;
cout << "Please enter details of the next player i.e. name, team, "
<< " level and points: ";
cin >> player3;

In the same way, we overload the stream insertion operator << in order to be able to use it as follows:
Player player3;
cout << "Player 3:" << endl;
cout << player3 << endl;
player3.set_team("BlueSwallows");
cout << "Player 3 is now in a new team:" << endl;
cout << player3 << endl;

The complete listing for the Player ADT and the application program you had to use to test it, is shown below.

Program listing:
Player.h class definition / interface for class Player:
#ifndef PLAYER_H
#define PLAYER_H
#include <iostream>
#include <string>
using namespace std;
class Player
{
public:
Player();
Player(string nam, string tem, int lev, int point);
~Player();
18

string get_name() const;


string get_team() const;
int get_level()const;
int get_points()const;
void set_name(string n);
void set_team(string t);
void set_level(int l);
void set_points(int p);
void reset(string nam, string tem, int lev, int point);
void requestHint()
friend Player operator++(Player &P);
friend Player operator--(Player &P);
friend bool operator>(const Player &player1, const Player
&player2);
friend bool operator==(const Player &player1, const Player
&player2);
friend istream & operator>>(istream & ins, Player & P);
friend ostream & operator<<(ostream & out, const Player & P);

private:
string name;
string team;
int level;
int points;
};
#endif

Implementation file: Player.cpp


#include "Player.h"
#include <iostream>
#include <string>
using namespace std;

Player::Player()
{
name = "Player 0";
team = "Team 0";
level = 0;
points = 0;
}

Player::Player(string nam, string tem, int lev, int point)


{
name = nam;
team = tem;
level = lev;
points = point;
}

Player::~Player()
{
cout<<"Game Over!" << endl;
}

string Player::get_name() const


{
return name;
}
19 COS1512/202/2/2011

string Player::get_team() const


{
return team;
}

int Player::get_level()const
{
return level;
}

int Player::get_points()const
{
return points;
}

void Player::set_name(string n)
{
name = n;
}

void Player::set_team(string t)
{
team = t;
}

void Player::set_level(int l)
{
level = l;
}

void Player::set_points(int p)
{
points = p;
}

void Player::reset(string nam, string tem, int lev, int point)


{
name = nam;
team = tem;
level = lev;
points = point;
}

void Player:: requestHint()


{
cout << "Please give me a hint" << endl;
--*this;
}
Player operator++(Player &P)
{
++P.points;
if (P.points % 100 == 0)
P.level++;
return P;
}
20

Player operator--(Player &P)


{
P.points = P.points - 10;
if (P.points / 100 < P.level)
--P.level;
return P;
}

bool operator>(const Player &player1, const Player &player2)


{
if (player1.points > player2.points)
return true;
return false;
}

bool operator==(const Player &player1, const Player &player2)


{
if (player1.team == player2.team)
return true;
return false;
}

istream & operator>>(istream & ins, Player & P)


{
ins >> P.name;
ins >> P.team;
ins >> P.points;
ins >> P.level;
return ins;
}

ostream & operator<<(ostream & out, const Player & P)


{
cout << "Player : " << P.name << endl;
cout << "Team : " << P.team << endl;
cout << "points : " << P.points << endl;
cout << "level : " << P.level << endl;
return out;
}

Application file: Videogame.cpp


#include <iostream>
#include <string>
#include "Player.h"

using namespace std;

int main() {
Player player1;
Player player2("Jane", "BlueSwallows", 1, 99);
Player player3;
cout << "Player 1:" << endl;
cout << player1 << endl;
cout << "Player 2:" << endl;
cout << player2 << endl;

player1.reset("Peter", "BlueSwallows", 2, 109);


cout << "New Player 1:" << endl;
21 COS1512/202/2/2011

cout << player1 << endl;

player1.requestHint();
++player2;
cout << "Player 1:" << endl;
cout << player1 << endl;
cout << "Player 2:" << endl;
cout << player2 << endl;

if (player1 == player2)
cout << player1.get_name() << " and " << player2.get_name()
<< " are both in team "
<< player1.get_team()<< endl;
else cout << player1.get_name() << " and " << player2.get_name()
<< " are not in the same team" << endl;

if (player1 > player2)


cout << player1.get_name() << " won" << endl << endl;
else cout << player2.get_name() << " won" << endl << endl;

cout << "Please enter details of the next player i.e. name, team, "
<< " level and points: ";
cin >> player3;
cout << "Player 3:" << endl;
cout << player3 << endl;

player3.set_team("BlueSwallows");
cout << "Player 3 is now in a new team:" << endl;
cout << player3 << endl;

return 0;
}

Output:
Player 1:
Player : Player 0
Team : Team 0
points : 0
level : 0

Player 2:
Player : Jane
Team : BlueSwallows
points : 99
level : 1

New Player 1:
Player : Peter
Team : BlueSwallows
points : 109
level : 2

Game Over!
Game Over!
Player 1:
Player : Peter
Team : BlueSwallows
points : 99
level : 1
22

Player 2:
Player : Jane
Team : BlueSwallows
points : 100
level : 2

Peter and Jane are both in team BlueSwallows


Jane won

Please enter details of the next player i.e. name, team, level and points:
Alex
Redsoxc 3 209
Player 3:
Player : Alex
Team : Redsoxc
points : 3
level : 209

Player 3 is now in a new team:


Player : Alex
Team : BlueSwallows
points : 3
level : 209

Game Over!
Game Over!
Game Over!
Press any key to continue . . .

Question 5 [max of 5 marks]

For this question, you had to overload the ++, --, > and == operators of the class Player, as member functions.
The same application file as in Question 4 should be used, and it should produce the same output.

Consider the new prototypes:


Player operator++();
Player operator--();
bool operator>(const Player &player2) const;
bool operator==(const Player &player2) const;
Note that the operator++() and operator--() member functions have no parameters and that the
operator>() and operator==() member functions each has only one parameter passed to it, instead of two
parameters as for a friend function. For instance operator== determines whether the parameter passed and the calling
object have the same team member variable. For example, consider the statement:
if (x == y).cout << “Equal”;
where x would represent the calling object and y the argument being passed to member function operator==().
With the definition of operator== as a member function, we have to choose one of the objects to be the calling
object. In contrast, with operator== as a non-member friend function (as in question 4), we do not need to do so,
with the result that both parameters are treated equally.

Note also that for member functions operator>() and operator==() the parameters are declared as constant
references to guarantee that these parameters are not modified by the calling member function (see pages 616 – 617
of Savitch 6th edition / pages 660 -661 of Savitch 7th edition) and the const at end of the prototype is a guarantee
that the calling object itself will not be modified. For example, the statement below should not modify either x, or y
23 COS1512/202/2/2011

in any possible way.


if (x == y).cout << “Equal”;

The implementation of the member function operator==() has a type qualifier (see page 543, Savitch 6th edition
/ page 575 7th edition for a definition). In other words we had to insert Player:: in the implementation. However
the implementation of operator==() in question 4 has no type qualifier, since the operator is not a member
function but rather a friend function.

bool Player::operator==(const Player &player2) const


{
if (this->team == player2.team)
return true;
return false;
}

Here this->team represent the member variable of the calling object, while player2.team refer to the
member variable of the object being passed as a parameter.

We use the this pointer to refer to the calling object (*this). See Appendix 7 page 990 Savich 6th edition / page
1044 Savitch 7th edition and chapter 11 of Tutorial Letter 501 (Study Guide), section 11.5 for more on the *this.

Many students find this version of operator== rather confusing because it has only one parameter. For the purposes
of this module, we prefer defining operators as friend functions.

Reference for member functions: Appendix 8 page 993 Savich 6th edition / page 1047 Savitch 7th edition and
chapter 11 of Tutorial Letter 501 (Study Guide), section 11.4.

Changes to the interface and implementation of the class Player to overload the ++, --, > and == operators as
member functions, are shown in bold.

Changes in the interface of class Player (Player.h) shown in bold:

#ifndef PLAYER_H
#define PLAYER_H
#include <iostream>
#include <string>
using namespace std;
class Player
{
public:
Player();
Player(string nam, string tem, int lev, int point);
~Player();
string get_name() const;
string get_team() const;
int get_level()const;
int get_points()const;
void set_name(string n);
void set_team(string t);
void set_level(int l);
void set_points(int p);
void reset(string nam, string tem, int lev, int point);
Player operator++();
Player operator--();
bool operator>(const Player &player2) const;
24

bool operator==(const Player &player2) const;


friend istream & operator>>(istream & ins, Player & P);
friend ostream & operator<<(ostream & out, const Player & P);

private:
string name;
string team;
int level;
int points;
};
#endif

Changes in implementation file: Player.cpp

Player Player::operator++()
{
++this->points;
if (this->points % 100 == 0)
this->level++;
return *this;
}

Player Player::operator--()
{
this->points = this->points - 10;
if (this->points / 100 < this->level)
--this->level;
return *this;
}

bool Player::operator>(const Player &player2) const


{
if (this->points > player2.points)
return true;
return false;
}

bool Player::operator==(const Player &player2) const


{
if (this->team == player2.team)
return true;
return false;
}

Question 6 [This question has not been marked. A max of 5 marks if you attempted
this question]
Discussion:

For this question you had to overload the << and the >> operators for class Module (defined in question 1). The
overloaded stream extraction operator >> should read or extract values for an object of class Module either from the
keyboard or from a file. The overloaded stream insertion operator << should display the data for a module either on
25 COS1512/202/2/2011

the screen or print it to a file.

You should have written a program that inputs the name of a lecturer, and the program should then use the
overloaded >> operator to extract Module objects one by one from a data file (Modules.dat), find all the
modules taught by the lecturer, and save those modules into an array. Once all the modules in the file
Modules.dat taught by the lecturer has been placed in the array, the program should use the array to determine
the total number of students taught by the lecturer, as well as the average number of students per module taught by
the lecturer. The program should then display the names of the modules, the total number of students taught by the
lecturer, and the average number of students per module taught by the lecturer, on the screen.

Changes to the interface and implementation of class Module as defined in question 1, are shown in bold. You
should have used separate compilation.

Program code:
Module.h:
#ifndef MODULE_H
#define MODULE_H
#include <iostream>
#include <fstream>
#include <string>
using namespace std;

class Module
{
public:
friend istream & operator >> (istream & ins, Module & m);
friend ostream & operator << (ostream & outs, const Module & m);
Module();
Module(string n, string c, string l, int nr);
void setModName(string n);
void setModCode(string c);
void setLecturer(string l);
void setNrStdts(int n);
string getModName();
string getModCode();
string getLecturer();
int getNrStdts();
private:
string moduleName;
string moduleCode;
string lecturer;
int nrStudents;
};
#endif

Module.cpp:
#include <iostream>
#include <string>
#include <fstream>
#include "Module.h"
using namespace std;

//implementation
Module::Module()
{
moduleName = " ";
moduleCode = "0000000";
26

lecturer = " ";


nrStudents = 0;
}

Module::Module(string n, string c, string l, int nr)


{
moduleName = n;
moduleCode = c;
lecturer = l;
nrStudents = nr;
}

void Module::setModName(string n)
{
moduleName = n;
}

void Module::setModCode(string c)
{
moduleCode = c;
}

void Module::setLecturer(string l)
{
lecturer = l;
}

void Module::setNrStdts(int n)
{
nrStudents = n;
}

string Module::getModName()
{
return moduleName;
}

string Module::getModCode()
{
return moduleCode;
}

string Module::getLecturer()
{
return lecturer;
}

int Module::getNrStdts()
{
return nrStudents;
}

istream & operator >> (istream & ins, Module & m)


{
string n, c, l;
int nrS;
getline(ins, n,'\n');
m.setModName(n);
27 COS1512/202/2/2011

ins >> c;
m.setModCode(c);
ins.get(); //to extract the '/n' before the lecturer's name,
//otherwise the getline will not extract the lecturer's name
//correctly
getline(ins, l,'\n');
m.setLecturer(l);
ins >> nrS;
m.setNrStdts(nrS);
ins.get();//to extract the '/n' before the next module's name,
//otherwise the getline will not extract the module's name
//correctly
return ins;
}

ostream & operator << (ostream & outs, const Module & m);
{
outs << m.moduleName << endl;
outs << m.moduleCode << endl;
outs << m.lecturer << endl;
outs << m.nrStudents << endl;
}

TestModuleArray.cpp
#include <iostream>
#include <fstream>
#include "Module.h"
using namespace std;

int main()
{
ifstream infile;
ofstream outfile;
Module allModules[20];
Module m;
int nrModules, totNrStudents, avgNrStdts;
string theLecturer;

cout << "Enter lecturer's name: ";


getline(cin, theLecturer);

infile.open("Modules.dat");
if (infile.fail())
{ cout << "Input file not available \n";
exit(1);
}

nrModules = 0;
while (infile >> m)
{
if (m.getLecturer() == theLecturer)
{
allModules[nrModules] = m;
nrModules++;
}
}
28

totNrStudents = 0;
cout << theLecturer << " teaches the following modules:" << endl;
for (int i = 0; i < nrModules; i++)
{
cout << allModules[i].getModName() << endl;
totNrStudents += allModules[i].getNrStdts();
}
avgNrStdts = totNrStudents/nrModules;

cout << endl << theLecturer << " teaches " << totNrStudents << " students
in total." << endl;
cout << endl << "The average number of students per module for " <<
theLecturer
<< " is " << avgNrStdts << endl;

return 0;
}
Input (Modules.dat):
Introduction to Programming I
COS1511
Mrs Schoeman
2534
Introduction to Programming I
COS1511
Mrs du Plessis
2534
Introduction to Programming II
COS1512
Mrs Schoeman
534
Introduction to Programming II
COS1512
Mrs du Plessis
534

Output:
Enter lecturer's name: Mrs Schoeman
Mrs Schoeman teaches the following modules:
Introduction to Programming I
Introduction to Programming II

Mrs Schoeman teaches 3068 students in total.

The average number of students per module for Mrs Schoeman is 1534
Press any key to continue . . .

©Unisa
2011

You might also like