5.7.1. The Time Structure Example (1)

Time: 00:13:00 | Download: Large Small | Streaming
Review
The Time example architecture. The Time example consists of three separate files organized in a client-supplier (or client-server) architecture. A supplier comprises general, reusable data structures and functions that provide a specific service. Think of suppliers as library code, not a complete program by itself, but providing a service application programs can use1. Developers typically separate the supplier's declarations and definitions, putting the declarations in header files and the definitions in source-code files. In this example, the supplier consists of Time.h, containing the Time structure and function declarations, and Time.cpp, containing the function definitions (i.e., bodies).

Following the top down implementation strategy, driver.cpp represents the client (i.e., an application program). It's a pseudo-client because it's not a "real" application - it doesn't solve a real problem - it's just a stand-in testing the code provided by the supplier files. Client files #include the supplier's header file, and the linker or loader links the object files (from the application and supplier code) into a complete application. A "real" client may have many files and use all or part of many suppliers.

The first structure example uses time as it represents a familiar concept: time expressed as hours, minutes, and seconds. And adding two amounts of time together should also be a familiar operation. Your familiarity with time will hopefully provide a sufficient foundation to understand the programming constructs the figures illustrate. Note that the next chapter modifies this example by changing the print function parameter slightly and adding a read function.

struct Time
{
	int	hours;
	int	minutes;
	int	seconds;
};

// function declarations or prototypes
Time make_time(int h, int m, int s);
Time make_time(int s);
Time add(Time t1, Time t2);
void print(Time t);
Time.h. All client files using Time-supplier features must #include this header file. The header specifies the Time structure consistently for all client files. It also provides the function declarations or prototypes2 necessary for the compiler to translate the program into machine code. The Time structure specification must precede the function prototypes. The next chapter explains this process in more detail.
#include <iostream>
#include "Time.h"
using namespace std;

Time make_time(int h, int m, int s)						// (a)
{
	Time	temp;

	temp.hours = h;
	temp.minutes = m;
	temp.seconds = s;

	return temp;
}

Time make_time(int s)								// (b)
{
	Time	temp;

	temp.hours = s / 3600;
	s %= 3600;		// shortcut for s = s % 3600;
	temp.minutes = s / 60;
	temp.seconds = s % 60;

	return temp;
}

Time add(Time t1, Time t2)							// (c)
{
	int	i1 = t1.hours * 3600 + t1.minutes * 60 + t1.seconds;
	int	i2 = t2.hours * 3600 + t2.minutes * 60 + t2.seconds;

	return make_time(i1 + i2);
}

void print(Time t)								// (d)
{
	cout << t.hours << ":" << t.minutes << ":" << t.seconds << endl;
}
Time.cpp. The supplier functions need the structure specification but not the function declarations. However, they cause no harm if they agree with the function definitions in this file. The order of the #include directives is insignificant.
  1. The function creates, fills, and returns a Time structure object. It populates the structure fields with the data passed into its parameters h, m, and s.
  2. An overloaded function making a Time structure object by converting an amount of time passed in as seconds, s, into an equivalent amount expressed as hours, minutes, and seconds.
    • 3600 seconds = 60 minutes/hour × 60 seconds/minute.
  3. The function adds two Time objects by converting each into a single integer representing the time as seconds. It adds the seconds and calls the second make_time function to convert the sum to a Time object.
    • 3600 seconds = 60 minutes/hour × 60 seconds/minute
    • 60 minutes = 60 seconds/minute
  4. The function takes a Time object parameter, t, retrieves the field values with the dot operator, and prints them with the inserter operator, separating the fields with colons.
#include <iostream>
#include "Time.h"
using namespace std;

int main()
{
	Time t = make_time(3666);
	print(t);

	Time s = make_time(1, 30, 4);
	print(s);

	Time u = add(t, s);		// adds two Time structs, saves the sum in u
	print(u);			// prints the sum saved in u

	return 0;
}
driver.cpp. The driver tests the supplier's functions by calling each with appropriate arguments. Programmers manually verify the functions' correct behavior by examining their return values. It's a common practice for programmers to "hard code" or embed the test data in the driver because it isn't a "real" program operating on actual data.

The preprocessor and compiler component process Time.cpp and driver.cpp separately, producing an object file (Time.obj and driver.obj on Windows systems, and Time.o and driver.o on others) for each. The linker or loader links the object files forming the final executable.

#include <iostream>
#include <iomanip>
#include "Time.h"
using namespace std;
	. . .
void print(Time t)
{
	cout.fill('0');
	cout << t.hours << ":" << setw(2) << t.minutes << ":" <<
		setw(2) << t.seconds << endl;
	cout.fill(' ');
}
Formatted output: print revisited. When displaying time, it's customary to show the minutes and seconds as two-digit numbers (with values less than 10 formatted with a leading '0'). The function formats the minutes and seconds with the setw manipulator, which requires the <iomanip> header file. The order of inclusion is not significant, but both #include directives must come before the using statement.

cout is an instance (i.e., an object) of the ostream class, which has a member function named fill. The program calls fill with the dot operator. Please see General Object-Oriented Method and Function Calls for a brief review.


  1. We have been using this programming model all semester when we #include <iostream> and then use cout or cin. iostream is a header file containing the specifications for the basic C++ input and output streams but as classes rather than structures. The linker or loader extracts the executable code from a library and links it with our compiled code.
  2. Function declarations, called prototypes, are a fundamental C++ feature. Naming the feature suggests its significance and facilitates discourse between programming professionals. The next chapter covers prototypes in detail.