9.15.1. The Time Class Example

Time: 00:04:04 | Download: Large, Large (CC), Small | Streaming, Streaming (CC) | Slides: PDF, PPTX
Review

The concept of time makes a useful programming example because it's familiar and, in the problem's restricted context, consists of only a few discrete values. Chapter 4 used it to demonstrate structures, while Chapter 5 modified it to demonstrate three ways of passing structure arguments to functions. It appears throughout this chapter, demonstrating many object-oriented programming features. The final version unites the previous examples, presenting them as a complete single-class program highlighting the conversion from a structure to a class. The Time class example consists of three files: Time.h contains the class specification; Time.cpp contains the member function definitions; and driver.cpp is a simple client program that uses the Time class. Given the previous detailed examples, this section presents the files with minimal elaboration.

The Time UML class diagram:
Time
-----------------
-hours : int
-minutes : int
-seconds : int
-----------------
+Time()
+Time(h : int, m : int, s : int)
+Time(s : int)
+add(t2 : Time) : Time
+print() : void
+read() : void
Converting Structure Function To Member Functions
Structure Version (2) Member Functions Notes
Time() (a)
Time make_time(int, int, int) Time(int, int, int) (b)
Time make_time(int) Time(int)
Time add(Time, Time) Time add(Time) (c)
void print(Time&) void print()
void read(Time*) void read()
The Time class: UML diagram and member functions. The member functions' names, parameters, and return types match the operations in the UML class diagram.
  1. A function is not needed to create an "empty" structure object.
  2. Constructors replace the make_time functions.
  3. Notice that the member and structure functions have the same total number of parameters. However, the member functions always "hide" one - the implicit this parameter, but structure function parameters are always explicitly visible inside the parentheses. Programs can pass explicit parameters by value, by reference, or by pointer, depending on the need.

The Time Class Program

class Time
{
    private:
        int hours;
        int minutes;
        int seconds;

    public:
        Time() : hours(0), minutes(0), seconds(0) {}
        Time(int h, int m, int s)
            : hours(h), minutes(m), seconds(s) {}
        Time(int s);

        Time add(Time t2);

        void print();
        void read();
};
class Time
{
    private:
        int hours = 0;
        int minutes = 0;
        int seconds = 0;

    public:
        Time() {}
        Time(int h, int m, int s)
            : hours(h), minutes(m), seconds(s) {}
        Time(int s);

        Time add(Time t2);

        void print();
        void read();
};
Time.h: Time class specification. The overall class specification follows the typical pattern: member variables are private, and member functions are public. Programmers can initialize the member variables with a default constructor, or in the class specification with a "dummy" default constructor. Recognizing that the add, print, and read functions have an implicit this parameter, binding them to an object. This observation is crucial for understanding member function calls.

 

#include <iostream>
#include <iomanip>
#include "Time.h"
using namespace std;


Time::Time(int s)
{
    hours = s / 3600;
    s %= 3600;
    minutes = s / 60;
    seconds = s % 60;
}


void Time::print()
{
    cout.fill('0');
    cout << hours << ":" << setw(2) << minutes << ":" <<
        setw(2) << seconds << endl;
    cout.fill(' ');
}
Time Time::add(Time t2)
{
    int i1 = hours * 3600 + minutes * 60 + seconds;
    int i2 = t2.hours * 3600 + t2.minutes * 60 + t2.seconds;

    return Time(i1 + i2);
}


void Time::read()
{
    cout << "Please enter the hours: ";
    cin >> hours;

    cout << "Please enter the minutes: ";
    cin >> minutes;

    cout << "Please enter the seconds: ";
    cin >> seconds;
}
 
 
Time.cpp: Time class member functions. Whenever a statement accesses a member variable (e.g., hours, minutes, or seconds) without a dot operator on the left, that variable temporarily "belongs" to the object calling the function, bound by this this pointer. The add function illustrates the distinction:

 

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


int main()
{
    Time t;			// (a)

    t.read();			// (b)
    t.print();

    Time s(1, 30, 4);		// (c)
    s.print();

    t.add(s).print();		// (d)

    //Time u = t.add(s);	// (e)
    //u.print();

    return 0;
}
driver.cpp: Time class example client. Programs cannot call member functions without binding them to an object. Programs pass the address of the object on the left-hand side of the dot operator to the this pointer in the member function.
  1. The default constructor.
  2. The function call passes t by pointer, making it an INOUT parameter.
  3. The general constructor initializes the member variables.
  4. The dot operator is left associative (evaluated left-to-right): (t.add(s)).print.
  5. It is easier to see the implicit or this object in the alternate version. Furthermore, while (d) is syntactically correct and works with most compilers, it failed on an older release of the of Visual Studio IDE compiler. Surprisingly, the command-line version of the same compiler correctly compiled (d), while both compiled (e).