You are on page 1of 27

COS1512/Solution to workshop exercises/2/2012

Solution to workshop exercises


Introduction to Programming II

COS1512
Semester 2

School of Computing

Bar code
CONTENTS

1  INTRODUCTION ............................................................................................................................ 3 

2  SOLUTION TO TO WORKSHOP EXERCISES ............................................................................. 3 


Question 2.………………………………………………………………………………………………………………4 

Question 3.………………………………………………………………………………………………………………6 

Question 4 (Bonus Question)………………………………………………………………………………………..21 

Question 5…………….……………………………………………………………………………………………….26 

2
COS1512/ Solution to workshop exercises

1 INTRODUCTION

The purpose of this tutorial letter is to supply the solution for the workshop exercises offered in the
document Workshop Exercises.

2 SOLUTION TO WORKSHOP EXERCISES

The workshop questions were given in the document Workshop Exercises. If you haven't
attempted to do the workshop problems yet, we recommend that you tackle them before referring
to these solutions.

Question 1

The code in bold should be added to the skeleton code for the class declaration. This should be
saved as TimeType.h.

Program Listing:
#ifndef TIMETYPE_H

#define TIMETYPE_H

#include <iostream>

#include <string>

using namespace std;

//prototype of TimeType class

class TimeType

public:

friend ostream& operator<<(ostream& sout, const TimeType &tt);

friend TimeType operator-(const TimeType &tt1, const TimeType &tt2);

TimeType();

TimeType(int initHrs, int initMins, int initSecs);

int GetHours() const;

int GetMins() const;

3
int GetSecs() const;

void Set(int h, int m, int s);

int TimeToSecs() const;

void SecsToTime(const int s);

~TimeType();

private:

int hrs; //hrs < 24. If hrs is incremented to 24 it should be reset to 0

int mins; //mins < 60

int secs; //secs < 60

};

#endif

Question 2

The following program listing should have been produced, after completing steps 3.5 – 3.12. This
should have been saved as TestTimeType.cpp and added to a project, e.g.
TestTimeType.dev.

Program Listing:

//main application file to test class TimeType

//Question 2 for workshop: Save in TestTimeType.cpp

//Also used in question 3

#include <iostream>

#include <string>

#include "TimeType.h"

using namespace std;

int main()

TimeType time1;

int h,m,s;

4
COS1512/ Solution to workshop exercises

// Question 3.5

h = time1.GetHours();

m = time1.GetMins();

s = time1.GetSecs();

cout << "time1 constructed with default constructor: Hours "

<< h << " minutes = " << m << " seconds = " << s << endl << endl;

// Question 3.6

time1.Set(13,23,59);

h = time1.GetHours();

m = time1.GetMins();

s = time1.GetSecs();

cout << "time1 set to a new value: Hours = " << h << " minutes = " << m

<< " seconds = " << s << endl << endl;

// Question 3.8

TimeType time2(5,30,19);

h = time2.GetHours();

m = time2.GetMins();

s = time2.GetSecs();

cout << "time2 constructed with overloaded constructor: Hours = " << h

<< " minutes = " << m << " seconds = " << s << endl << endl;

// Question 3.9

int allSecs;

allSecs = time1.TimeToSecs();

h = time1.GetHours();

m = time1.GetMins();

s = time1.GetSecs();

cout << " time1 Hours = " << h

<< " minutes = " << m << " seconds = " << s << endl

5
<< " converted to seconds is " << allSecs << " seconds"

<< endl;

// Question 3.10

TimeType time3;

time3.SecsToTime(allSecs);

h = time3.GetHours();

m = time3.GetMins();

s = time3.GetSecs();

cout << allSecs << " seconds converted to time is: Hours = "

<< h << " minutes = " << m << " seconds = " << s << endl

<< endl;

// Question 3.11

TimeType time4;

time4 = time1 - time2;

h = time4.GetHours();

m = time4.GetMins();

s = time4.GetSecs();

cout << "Time difference between time 1 and time 2: Hours = "

<< h << " minutes = " << m << " seconds = " << s << endl

<< endl;

// Question 3.12

cout << "time1: " << time1 << endl;

cout << "time2: " << time2 << endl;

cout << "time4: " << time4 << endl;

return 0;

Question 3

Create another source file TimeType.cpp with the contents below and add to
TestTimeType.dev.
6
COS1512/ Solution to workshop exercises

(NB: this is the implementation file). You should have produced the following implementation file
once steps 3.1 – 3.12 were completed.

// implementation file

#include <iostream>

#include <string>

#include "TimeType.h"

using namespace std;

//Default constructor

TimeType::TimeType()

hrs = 0;

mins = 0;

secs = 0;

//Overloaded constructor. Time is set according to incoming parameters

TimeType::TimeType(int initHrs, int initMins, int initSecs)

hrs = initHrs;

mins = initMins;

secs = initSecs;

int TimeType::GetHours() const

return hrs;

int TimeType::GetMins() const

return mins;

7
}

int TimeType::GetSecs() const

return secs;

//Time is set according to incoming parameters

void TimeType::Set(int h, int m, int s)

hrs = h;

mins = m;

secs = s;

TimeType::~TimeType()

cout << "Goodbye!" << endl;

int TimeType::TimeToSecs() const

int seconds;

seconds = hrs*60*60 + mins*60 + secs;

return seconds;

void TimeType::SecsToTime(const int s)

int remainder;

hrs = s /( 60 * 60 );

remainder = s % ( 60 * 60 );

mins = remainder / 60;


8
COS1512/ Solution to workshop exercises

secs = remainder % 60;

ostream& operator<<(ostream& sout, const TimeType &tt)

sout << tt.hrs <<':' << tt.mins << ':' << tt.secs;

return sout;

TimeType operator-(const TimeType &tt1, const TimeType & tt2)

int Time1 = tt1.TimeToSecs();

int Time2 = tt2.TimeToSecs();

int Time3 = Time1 - Time2;

TimeType Temp;

Temp.SecsToTime(Time3);

return Temp;

Discussion:

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:

TimeType.h

TimeType.cpp

TestTimeType.cpp

Tips for separate compilation with multiple files:

 Only the files with the cpp extension should be ‘added’ to the project.
 All files must be in the same directory or folder as the project file (the .dev file).
 Both the class specification (or interface) file (the .h file) and the implementation file (a
.cpp file) should contain a using namespace std; statement.
 The .cpp files must contain the preprocessor directive to include the .h files.

9
e.g. #include "TimeType.h"

Reference: Appendix A section 4 in Tutorial Letter 101 for more information.

Question 3.1

For this question, the default constructor which initialises the hours, minutes and seconds to 0 had
to be implemented.

Solution:

TimeType::TimeType()

hrs = 0;

mins = 0;

secs = 0;

Discussion:

A constructor is a member function that is automatically called when an object of the class is
declared. A constructor is used to initialize the values of the data members and to do any sort of
initialization that may be required. The constructor has the same name as the class and does not
return a value. The default constructor takes no arguments. The default constructor is invoked
when an object is declared like this:

TimeType t; (For more on default constructors – refer to pages 570-571 of Savitch 6th edition /
pages 602-604 of Savitch 7th edition / pages 598-600 of Savitch 8th edition)

Question 3.2

For this question, the member function GetHours() had to be implemented.

Solution:

int TimeType::GetHours() const {

return hrs;

Discussion:

GetHours() is an accessor member function. An accessor is a member function that accesses


the contents of an object but does not modify that object. The trailing const after the
10
COS1512/ Solution to workshop exercises

GetHours()signature means that the state of the object cannot be modified. That is, trying to
modify hrs, mins or secs in any way would produce a compilation error. For example the
statements marked by x are not permissible.

int TimeType::GetHours() const

hrs = hrs*10; x

mins++; x

secs = 2; x

return hrs;

GetMins() and GetSecs() are also examples of accessor member functions.


Reference: Savitch, pages 553 – 554 6th edition / pages 585-586 7th edition / pages 581-582 8th
edition

The const modifier can be used in other contexts as well. Ensure that you study the following
utilization of this modifier as well:

const Parameter Modifier - reference: Savitch pages 616 – 617 6th edition / pages 660-661 7th
edition / pages 650-653 8th edition

Question 3.3

For this question, the member function GetMins() had to be implemented.

Solution:

int TimeType::GetMins() const

return mins;

11
Question 3.4

For this question, the member function GetSecs()had to be implemented.

Solution:

int TimeType::GetSecs() const

return secs;

Question 3.5

To test the functions implemented above, the following statements had to be added to the file
TestTimeType.cpp:

TimeType time1;

int h,m,s;

h = time1.GetHours();

m = time1.GetMins();

s = time1.GetSecs();

cout << "time1 constructed with default constructor: Hours = "

<< h << " minutes = " << m << " seconds = " << s << endl

<< endl;

After compiling and executing TestTimeType.cpp. The following output was produced:
time1 constructed with default constructor: Hours = 0 minutes = 0 seconds = 0

Press any key to continue . . .

Question 3.6

For this question, member function Set() had to be implemented.

Solution:

void TimeType::Set(int h, int m, int s)

hrs = h;

mins = m;

12
COS1512/ Solution to workshop exercises

secs = s;

To test this function, the following statements were added to TestTimeType.cpp:

time1.Set(13,23,59);

h = time1.GetHours();

m = time1.GetMins();

s = time1.GetSecs();

cout << "time1 set to a new value: Hours = " << h

<< " minutes = " << m << " seconds = " << s << endl << endl;

After compiling and executing TestTimeType.cpp, the following output was produced:

time1 constructed with default constructor: Hours = 0 minutes = 0 seconds = 0

time1 set to a new value: Hours = 13 minutes = 23 seconds = 59

Press any key to continue . . .

Discussion:

The Set() member function is a mutator. A mutator is a member function that can modify an
object. Every non-const member function of a class is potentially a mutator. In the simplest case,
a mutator just assigns a new value to one of the data members of the class. In general, a mutator
performs some computation and modifies any number of data members (Reference: Savitch,
pages 553-554 6th edtion / pages 585-586 7th edition / pages 581-582 8th edition).

Question 3.7

For this question, the destructor had to be implemented:

Solution:

TimeType::~TimeType()

cout << "Goodbye!" << endl;

13
After compiling and running TestTimeType.cpp, the following output is produced:

time1 constructed with default constructor: Hours = 0 minutes = 0 seconds = 0

time1 set to a new value: Hours = 13 minutes = 23 seconds = 59

Goodbye!

Press any key to continue . . .

Discussion:

This destructor actually does not do anything special! Like constructors, destructors are also
functions and do not have a return type. However a class may have only one destructor and the
destructor has no parameters. The name of a destructor is the tilde character (~) followed by the
name of the class. The destructor automatically executes when the class object goes out of scope.
You will encounter more valid destructors as you advance to the second year programming
modules (Reference: Savitch, page 649 – 651 6th edition / page 693 -695 7th edition / page 683 -
685 8th edition.

Question 3.8

For this question, the overloaded constructor had to be implemented.

Solution:

TimeType::TimeType(int initHrs, int initMins, int initSecs)

hrs = initHrs;

mins = initMins;

secs = initSecs;

To test the overloaded constructor, the following statements were added to TestTimeType.cpp:

TimeType time2(5,30,19);

h = time2.GetHours();

m = time2.GetMins();

s = time2.GetSecs();

cout << "time2 constructed with overloaded constructor: Hours = "


<< h << " minutes = " << m << " seconds = " << s << endl
<< endl;

After compiling and executing TestTimeType.cpp, the following output was produced:
14
COS1512/ Solution to workshop exercises

time1 constructed with default constructor: Hours = 0 minutes = 0 seconds = 0

time1 set to a new value: Hours = 13 minutes = 23 seconds = 59

time2 constructed with overloaded constructor: Hours = 5 minutes = 30 seconds =


19

Goodbye!

Goodbye!

Press any key to continue . . .

Discussion:
This redefinition overloads the constructor name TimeType so that it may have three arguments.
The overloaded constructor has the same name as the class and does not return a value. This
constructor allows you to instantiate objects of type TimeType, as shown below:
TimeType t1(0,7,30);

TimeType t2(3,4,5);

Question 3.9

For this question the member function TimeToSecs() had to be implemented.

Solution:

int TimeType::TimeToSecs() const

int seconds;

seconds = hrs*60*60 + mins*60 + secs;

return seconds;

To test this function, the following statements were added to TestTimeType.cpp:

int allSecs;

allSecs = time1.TimeToSecs();

h = time1.GetHours();

m = time1.GetMins();

15
s = time1.GetSecs();

cout << " time1 Hours = " << h

<< " minutes = " << m << " seconds = " << s << endl

<< " converted to seconds is " << allSecs << " seconds"

<< endl;

After compiling and executing TestTimeType.cpp, the following output was produced:

time1 constructed with default constructor: Hours = 0 minutes = 0 seconds = 0

time1 set to a new value: Hours = 13 minutes = 23 seconds = 59

time2 constructed with overloaded constructor: Hours = 5 minutes = 30 seconds =


19

time1 Hours = 13 minutes = 23 seconds = 59

converted to seconds is 48239 seconds

Goodbye!

Goodbye!

Press any key to continue . . .

Question 3.10

For this question the function SecsToTime() had to be implemented.

Solution:

void TimeType::SecsToTime(const int s)

int remainder;

hrs = s /( 60 * 60 );

remainder = s % ( 60 * 60 );

mins = remainder / 60;

secs = remainder % 60;

To test this function, the following statements were added to TestTimeType.cpp:

TimeType time3;

16
COS1512/ Solution to workshop exercises

time3.SecsToTime(allSecs);

h = time3.GetHours();

m = time3.GetMins();

s = time3.GetSecs();

cout << allSecs << " seconds converted to time is: Hours = "

<< h << " minutes = " << m << " seconds = " << s << endl

<< endl;

After compiling and executing TestTimeType.cpp, the following output was produced:

time1 constructed with default constructor: Hours = 0 minutes = 0 seconds = 0

time1 set to a new value: Hours = 13 minutes = 23 seconds = 59

time2 constructed with overloaded constructor: Hours = 5 minutes = 30 seconds =


19

time1 Hours = 13 minutes = 23 seconds = 59

converted to seconds is 48239 seconds

48239 seconds converted to time is: Hours = 13 minutes = 23 seconds = 59

Goodbye!

Goodbye!

Goodbye!

Press any key to continue . . .

Question 3.11

For this question the operator- had to be implemented.

Solution:

TimeType operator-(const TimeType &tt1, const TimeType & tt2)

int Time1 = tt1.TimeToSecs();

17
int Time2 = tt2.TimeToSecs();

int Time3 = Time1 - Time2;

TimeType Temp;

Temp.SecsToTime(Time3);

return Temp;

To test this function, the following statements were added to TestTimeType.cpp:

TimeType time4;

time4 = time1 - time2;

h = time4.GetHours();

m = time4.GetMins();

s = time4.GetSecs();

cout << "Time difference between time 1 and time 2: Hours = "

<< h << " minutes = " << m << " seconds = " << s << endl

<< endl;

After compiling and executing TestTimeType.cpp, the following output was produced:

time1 constructed with default constructor: Hours = 0 minutes = 0 seconds = 0

time1 set to a new value: Hours = 13 minutes = 23 seconds = 59

time2 constructed with overloaded constructor: Hours = 5 minutes = 30 seconds =


19

time1 Hours = 13 minutes = 23 seconds = 59

converted to seconds is 48239 seconds

48239 seconds converted to time is: Hours = 13 minutes = 23 seconds = 59

Goodbye!

Time difference between time 1 and time 2: Hours = 7 minutes = 53 seconds = 40

Goodbye!

Goodbye!

Goodbye!
18
COS1512/ Solution to workshop exercises

Goodbye!

Press any key to continue . . .

Discussion:

Operator overloading extends the C++ language. Basically it allows us to make operators work
with user defined types. When we overload operators they should also conform to the built-in
version. In other words the overloaded operator should be able to be used in a similar manner as
the built-in operator.

An important point to remember with return types and signatures of operator overloaded functions
is that they are standard. Therefore the general syntax to overload the operator- as a non-
member friend function is:

className operator-(const className & firstobject,

const className & secondobject){

//algorithm to perform operation

return temp;

In fact any arithmetic binary operator may be implemented in this way. In other words to overload
operators +, * or / merely replace – above with +, *, / respectively.

Please consider these explanations with relation to the Money class provided in Savitch, Section
11.2, on page 619 6th edition / page 663 7th edition / page 655 8th edition.

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 6th edition / pages 644 – 662 7th
edition / pages 632 – 655 8th edition). Some experts believe that friend functions should be
generally avoided because 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, page 993 of Savitch 6th edition / page 1047 of Savitch 7th edition / page 1034 of
Savitch 8th edition for a complete discussion as to why defining operators as friend functions is
preferable.

Question 3.12

For this question the operator<< had to be implemented.

19
Solution:

ostream& operator<<(ostream& sout, const TimeType &tt)

sout << tt.hrs <<':' << tt.mins << ':' << tt.secs;

return sout;

To test this function, the following statements were added to TestTimeType.cpp:

cout << "time1: " << time1 << endl;

cout << "time2: " << time2 << endl;

cout << "time4: " << time4 << endl;

After compiling and executing TestTimeType.cpp, the following output was produced:

time1 constructed with default constructor: Hours = 0 minutes = 0 seconds = 0

time1 set to a new value: Hours = 13 minutes = 23 seconds = 59

time2 constructed with overloaded constructor: Hours = 5 minutes = 30 seconds =


19

time1 Hours = 13 minutes = 23 seconds = 59

converted to seconds is 48239 seconds

48239 seconds converted to time is: Hours = 13 minutes = 23 seconds = 59

Goodbye!

Time difference between time 1 and time 2: Hours = 7 minutes = 53 seconds = 40

time1: 13:23:59

time2: 5:30:19

time4: 7:53:40

Goodbye!

Goodbye!

Goodbye!

20
COS1512/ Solution to workshop exercises

Goodbye!

Press any key to continue . . .

Discussion:

Consider the overloaded << operator and the statement:

cout << Time1 << Time2;

The first expression cout << Time1 would execute by making the call:

operator<<( cout, Time1 );

This call would then return a reference to cout as the value of cout << Time1 so the remaining
portion of the expression would be interpreted simply as cout << Time2. This would execute by
making the call:

operator<<(cout, Time2 );

We return by reference to allow this chaining to occur.

(Reference: Savitch, pages 626 – 635 6th edition / pages 670 – 679 7th edition / pages 664 – 667
8th edition)

Question 4 (Bonus Question)

For this question operator++, had to be implemented. We provide two possible solutions for
operator++. Either one could have been used in the implementation file TimeType.cpp.

Solution 1:

TimeType &operator++(TimeType &tt)

tt.secs++;

if (tt.secs > 59)

tt.secs = 0;

tt.mins++;

if (tt.mins > 59)

tt.mins = 0;

21
tt.hrs++;

if (tt.hrs > 23)

tt.hrs = 0;

return tt;

Solution 2:

TimeType &operator++(TimeType &tt)

int s;

s = tt.TimeToSecs();

++s;

tt.SecsToTime(s);

return tt;

The interface is changed accordingly, by including the prototype (shown in bold font):

#ifndef TIMETYPE_H

#define TIMETYPE_H

#include <iostream>

#include <string>

using namespace std;

//prototype of TimeType class

class TimeType {

public:

friend ostream &operator<<(ostream &sout, const TimeType &tt);

friend TimeType operator-(const TimeType &tt1, const TimeType &tt2);

friend TimeType &operator++(TimeType &tt);

TimeType();

TimeType(int initHrs, int initMins, int initSecs);

22
COS1512/ Solution to workshop exercises

int GetHours() const;

int GetMins() const;

int GetSecs() const;

void Set(int h, int m, int s);

int TimeToSecs() const;

void SecsToTime(const int s);

~TimeType();

private:

int hrs; //hrs < 24. If hrs is incremented to 24 it should

// be reset to 0

int mins; //mins < 60

int secs; //secs < 60

};

#endif

To test this function, the following statements were added to TestTimeType.cpp:

++time1;

h = time1.GetHours();

m = time1.GetMins();

s = time1.GetSecs();

cout << "time1 incremented once more: Hours = " << h

<< " minutes = " << m << " seconds = " << s << endl << endl;

After compiling and executing TestTimeType.cpp, the following output was produced:

time1 constructed with default constructor: Hours = 0 minutes = 0 seconds = 0

time1 set to a new value: Hours = 13 minutes = 23 seconds = 59

time2 constructed with overloaded constructor: Hours = 5 minutes = 30 seconds =

19

23
time1 Hours = 13 minutes = 23 seconds = 59

converted to seconds is 48239 seconds

48239 seconds converted to time is: Hours = 13 minutes = 23 seconds = 59

Goodbye!

Time difference between time 1 and time 2: Hours = 7 minutes = 53 seconds = 40

time1: 13:23:59

time2: 5:30:19

time4: 7:53:40

time1 incremented once: Hours = 13 minutes = 24 seconds = 0

Goodbye!

Goodbye!

Goodbye!

Goodbye!

Press any key to continue . . .

Discussion:

As mentioned earlier, an important point to remember with return types and signatures of operator
overloaded functions is that they are standard. Therefore the general syntax to overload the pre-
increment operator++ as a non-member friend function is:

className& operator++(className & whatever){

//increment whatever by 1

return whatever;

Most modern programming languages allow you to chain operations, that is, they allow several
operators to be used within the same statement. For example: total = a + b + c;. In view
of the fact that, one purpose of operator overloading is to create class operators that work
naturally like built-in operators, you must also create operators for your own classes to have the
same ability. For instance, for the increment operator ++, C++ will allow the following statements:

int a;

++++a;

24
COS1512/ Solution to workshop exercises

This implies that our operator must also be allowed to be used in the same way:

TimeType a;

++++a; // meaning: ++ ++ a;

As operator++ modifies the object, the object must be passed as a reference. The compiler
processes the statement from right to left. When the compiler processes ++a, it interprets it as a
call to operator++(a). Here a, is modified and returned as a reference. Thereafter a is passed
as a reference parameter in a second call to operator++(a). In order for the chaining process to
occur, a reference has to be returned so that a reference may be passed to the next operation in
the chain as operator++ expects a reference parameter (see diagram below).

++

call
operator++(a)

call
operat

The second part of the question required you to test the class Timetype also with the application
program shown below. To do this, open a new project and add the implementation file
TimeType.cpp to it. Type the application program shown below in the main file. The code for
this application program can be downloaded from the departmental website.

//The second main application file

#include <iostream>

#include <string>

#include "TimeType.h"

using namespace std;

int main()

TimeType time1(5, 30, 0);

TimeType time2;

cout << "time 1: " << time1 << endl;

25
cout << "time 2: " << time2 << endl;

time1.Set(23, 59, 55);

cout << "Incrementing time1 from 23:59:55:" << endl;

int LoopCount;

for (LoopCount = 1; LoopCount <=10; LoopCount++)

cout << time1 << ' ';

cout << ' ' ;

++time1;

cout << endl;

return 0;

Guidelines:

Create a second project, type in / copy the second main application file as given, save it as e.g.
TestTimeType2.cpp, add Timetype.cpp, compile and run.

Output Produced:

This produces following output:

time 1: 5:30:0

time 2: 0:0:0

Incrementing time1 from 23:59:55:

23:59:55 23:59:56 23:59:57 23:59:58 23:59:59 0:0:0 0:0:1 0:0:2 0:0:3


0:

0:4

Goodbye!

Goodbye!

Press any key to continue . . .

Question 5
For this question you had to classify each of the member functions in the class TimeType as
accessors or mutators.

26
COS1512/ Solution to workshop exercises

Accessors:

GetHours()

GetMins()

GetSecs()

TimeToSecs()

Mutators:

Set()

SecsToTime()

Unisa 2012

27

You might also like