cs1ch4sec6.htm
 

Chapter 4
 
Design with Functions


Section VI: Final Thoughts on Redesigning the Employee Salary Problem Section I: Decomposition Section II: Functions Section III: Output, Calculation, and Display Functions
Section IV: Parameters Section V: Tracing

  


Table of Contents

Learning C++:
An Index of Entry Points


2. The

of C++

A reference document on the basic elements of C++.



3. The Patterns



Index!



A. Simplifying 'main': Removing the Call to 'GetEmployeeInformation'
Our previous design separated getting the relevant employee information from performing the salary calculation. Another person analyzing this same problem might consider getting the employee information as part of calculating the salary. They could validly argue that getting the employee information is simply the first step in the algorithm for calculating the salary. From this perspective it is not 'main' that calls 'GetEmployeeInformation' but 'CalculateSalary' and the structure chart looks as follows:


A Revised Warning Label: In the structure chart above, the fact that 'GetRateOfPay' hangs off of 'GetEmployeeInformation' which in turn hangs off of ' CalculateSalary ' means that 'GetRateOfPay' is a task that is part of the task 'GetEmployeeInformation' which is, in turn, part of the task 'CalculateSalary'. In other words, 'CalculateSalary' calls 'GetEmployeeInformation' which calls 'GetRateOfPay'.

Since we have carefully modularized our code, this change in overall design has no effect on the design or implementation of most of the functions including 'GetEmployeeInformation' or 'GetRateOfPay'. The two functions that need to be modified are 'main' and 'CalculateSalary' because the call to 'GetEmployeeInfo' is moved from 'main' to 'CalculateSalary'.

Since we have changed the processing involved in 'CalculateSalary' by deciding to include the task of getting the employee information, the design of that module must change. The earlier analysis concluded that 'CalculateSalary' would receive the rate of pay and the hours worked. When we re-ask the question, "What does 'CalculateSalary' need to perform its task, we can't say that it needs the rate of pay and the hours worked because it, itself, will handle acquiring them. Thus, 'CalculateSalary' receives nothing.

The design now becomes:

CalculateSalary
Purpose: To calculate an employee's salary based on rate of pay
                and hours worked information input by a user.

Goal:     <employeeSalary>, a double, contains the employee's salary

Receives: NONE
Returns: <employeeSalary>

Algorithm:

    GetEmployeeInformation
    If Hours > 40 then
    {
      Regular Salary = 40 * Rate
      Overtime Rate = Rate * 1.5
      Overtime Salary = (Hours - 40) * Overtime Rate
      Employee Salary = Regular Salary + Overtime Salary
    }
    else
    {
      Employee Salary = Hours * Rate
    }

Given this design, the function declaration becomes:

double CalculateSalary();

Since the only change in the algorithm for 'CalculateSalary' is that the call to 'GetEmployeeInformation' previously found in 'main' is moved to the beginning of 'CalculateSalary', the new definition is easy to write. Creating this is therefore left as an exercise.

The code for the function 'main' also needs to be changed. However, the change is very simple. We simply remove the call to 'GetEmployeeInformation'. This too is left as an exercise.

B. Simplifying 'main': Removing the Loop
Some programmers and software engineers argue that 'main' should be kept as simple as possible. One way to further simplify 'main' for the employee salary problem would be to move the loop to a new function. We could call this new function 'Process Salaries' since its job would be to do all the work of inputting and calculating the employee salaries. In fact, it would do all the work except handle the opening and closing screens.

The program entitled 'ch3prg6.cpp' in Section VIII of Chapter 3 used a while loop to process the salary information for some unknown number of employees. In addition to dealing with individual salaries, this program output the number of employees processed. Someone might also be interested in the total amount of money paid out in salaries. Our task here will be design and implement such a program, shifting the 'while' loop out of 'main'. The structure chart for such a program might look like the one in figure 4.8 below


Observations on this structure chart:

  1. The function 'ProcessSalaries' takes the place of 'CalculateSalaries ' in 'main'.

  2. We have a new function called 'OutputTotals' that outputs the total number of employees processed and the total paid out in salaries.

  3. In section VIII of chapter 3 we pointed out that only the rate of pay needed to be treated as a priming read before the while loop. This means that getting the rate of pay must be separated from getting the hours worked. Therefore we need to drop the idea of a 'GetEmployeeInformation' function.
      There are two new functions in this design, 'ProcessSalaries' and 'OutputTotals', and both need to be designed. We will start with 'OutputTotals' since it is the easier of the two. The "Basic Output" design pattern tells us that this function should return nothing. Now, what does it receive?

      Following the same logic we used in designing the 'OutputSalary' function, it should be clear that this function receives whatever is to be output. In other words, it should receive the employee count and the total in salaries. Therefore, the design looks as follows:


      OutputTotals
      Purpose:    To output the number of employees processed
                  and the total in salaries
      Goal:       The number of employees and the total in
                  salaries is displayed
      
      Receives:   <employee count> an integer,
                  <total in salaries> a double
      Returns:    None
      
      Algorithm:
          Output <employee count>
          Output <total in salaries>
      
      Given this design the function declaration might look as follows:
      void OutputTotals(int empCount, double salaryTotal);

      Take a moment and try to write the definition yourself. Hint: You only need two lines of code inside the brackets. At the end of this section the complete code is provided so you can check your work.

      Now for 'ProcessSalaries'. What does it need to receive from 'main'? Note that in our new design all the real work takes place in 'ProcessSalaries. Since we have stripped 'main' of all but the simplest of functionality, there is nothing for it to give 'ProcessSalaries'. The answer then is that 'ProcessSalaries' receives nothing.

      To answer the question "what does "ProcessSalaries' return", we note that 'main', according to the new design, is expected to provide two totals to 'OutputSalaries'. Where does it get them from? Since all real processing takes place in "ProcessSalaries', it must return these totals to 'main'. Here then is the design for 'ProcessSalaries', minus the algorithm:

      ProcessSalaries
      Purpose:    To process employee information to output
                  individual salaries. Also, calculate 
                  the number of employees processed and the
                  total in salaries
      			
      Goal:       Each employee's salary is output, 
                  <employee count>, an integer,  holds the
                  number of employees,
                  <salary total>, a double, holds the total in
                  salaries
      
      Receives:   None
      Returns:    <employee count>, <<salary count>
      
      Using this, the declaration is as follows:
      void ProcessSalaries(int& employeeCount, double& totalSalaries);

      Now for the algorithm. It should be clear that the algorithm for this function uses the "While loop with a Priming Read" pattern. We could use this pattern to design the algorithm from scratch but most of the algorithm was provided in section 8 of chapter 3. Only the instructions to produce the two totals are missing. Here is the complete algorithm.

      Employee Count = 0
      Salary Total = 0
      
      Get the Rate of Pay for an employee
      While rate of pay >= 0  
      {
      	Get the Hours Worked for this employee
      	if Hours Worked is greater than 40
      	{
      		Regular Salary = 40 * Rate of Pay
      		Overtime Rate of Pay  = Rate of Pay * 1.5
      		Overtime Salary = Overtime Rate of Pay *
      		                  (Hours Worked - 40)
      		Full Salary = Regular Salary + Overtime Salary
      	}
      	else
      	{
      		Full Salary = Hours Worked * Rate of Pay
      	}	
      	Output the Full Salary
      	Add 1 to the Employee Count
      	Salary Total = Salary Total + Full Salary
      
      	Get the Rate of Pay for an employee
      }
      It is worth noting how we could use the algorithm for a program in chapter three as the algorithm for a function. Functions are like miniature programs and we can use all the tools from chapter 3 in designing their algorithms.

      It is now time to define 'ProcessSalaries'. One can either use the code from section 8 of chapter 3 as a guide or use the algorithm we just wrote. Here we will use the algorithm since usually one will not have pre-written code.

      The initializations and declarations are simple:

      void ProcessSalaries(int& employeeCount, double& totalSalaries)
      {	double rateOfPay;
      	double overtimeRateOfPay;
      
      	double regularSalary;
      	double overtimeSalary;
      	double fullSalary;
      	double hoursWorked;  // can be a fraction of an hour
      
      	employeeCount = 0;  // initialize the counter parameter to 0
      	totalSalaries = 0;  // initialize the salary total parameter to 0
      
      The only point worth commenting on is that the employee counter and the salary total variables are not declared in the code because they are already declared as parameters. They are, however, initialized in the code - to replace whatever garbage they contained when they were passed in.

      The next line of the algorithm is "Get the Rate of Pay for an Employee". In chapter three we translated this as a 'cout' - 'cin' pair. Now, however, we have a function called 'GetRateOffPay' to handle this. Notice that the rate of pay is treated as an input twice in the algorithm so we need to call 'GetRateOfPay' twice in the code. Here is the code so far:

      void ProcessSalaries(int& employeeCount, double& totalSalaries)
      {	  double rateOfPay;
      	  double overtimeRateOfPay;
      
      	  double regularSalary;
      	  double overtimeSalary;
      	  double fullSalary;
      	  double hoursWorked;  // can be a fraction of an hour
      
                employeeCount = 0;  // initialize the counter parameter to 0
      	  totalSalaries = 0;	  // initialize the salary total parameter to 0
      
      	  rateOfPay = GetRateOfPay();
      	  while (rateOfPay >= 0)
      	  {	.
      	 	.
      		rateOfpay = GetRateOfPay();
      	  }
      }
      
      All that is left to do is get the hours worked for the employee, calculate the salary, and update the totals. As an exercise, try completing this and then writing the full program, including 'main'. Below is the code for that full program. Note how simple 'main' has become.
      // A program to calculate the salaries for any number of employees and output the number
      // of employees processed and the total in salaries
      // File: ch4prg4.cpp
      // The Specifications go here
      
      #include <iostream.h>
      
      const 	int REGULAR_HOURS = 40;    // Number of hours before overtime 
      const   double OVERTIME_ADJUSTMENT = 1.5;  // Overtime pay adjustment
      const	int NUM_TIMES = 10;	   // Number of employees to work with
      
      void DisplayIntroScreen();
      /* Purpose:	To output a introductory message
         Goal:	The introductory message is displayed
         Receives:	NONE
         Returns:	NONE
      */
      
      void DisplayExitScreen();
      /* Purpose:	To output an exit message
          Goal:	The exit message is displayed
          Receives:	NONE
          Returns:	NONE
      */
      
      double GetRateOfPay();
      /* Purpose:	To get the rate of pay for an employee from a user
         Goal:	<rateOfPay>, a double,  contains the rate of pay for an employee
         Receives:    Nothing
         Returns      <rateOfPay>
      */
      
      double GetHoursWorked();
      /* Purpose:	To get the hours worked for an employee from a user
         Goal:	<hoursWorked>, a double,  contains the hours worked for an employee
         Receives:	Nothing
         Returns	<hoursWorked>
      */
      void OutputSalary (double salary);
      /*
      Purpose:	To output the salary of an employee
      Goal:		The screen displays the salary
      Receives:	<salary>, a double
      Returns		NONE
      */
      
      double CalculateSalary(double rate, double hours);
      /*
      Purpose:	To calculate an employee's salary
      Goal:		<employeeSalary>, a double, contains the employee's salary
      Receives:	<rate> a double, <hours> a double
      Returns:	<employeeSalary>
      */
      
      void OutputTotals(int empCount, double salaryTotal);
      /*
      Purpose:	To output the number of employees processed and the total in salaries
      Goal:		The number of employees and the total in salaries is displayed
      Receives:	The <employee count> an integer,  a double
      Returns:	None
      */
      
      void ProcessSalaries(int& employeeCount, double& totalSalaries);
      /*
      Purpose:	To process employee information to output individual salaries. Also, calculate 
      		the number of employees processed and the total in salaries
      Goal:		Each employee's salary is output, 
      		<employee count>, an integer,  holds the number of employees,
      		<salary total>, a double, holds the total in salaries
      
      Receives:	None
      Returns:	<employee count>, <salary count>
      */
      
       void main()
      // Purpose: 	to calculate the salaries for any number of employees and output the number
      // 		of employees processed and the total in salaries
      // Receives:	NONE
      // Returns:	NONE
      {	int numEmployees;
      	double totalInSalaries;
      	DisplayIntroScreen();
      	ProcessSalaries(numEmployees, totalInSalaries);
      	OutputTotals(numEmployees, totalInSalaries);
      	DisplayExitScreen();
      }
      
      void DisplayIntroScreen()
      {	cout << "Welcome to this program\n"; // You should be more creative
      }
      
      void DisplayExitScreen()
      {	cout << "\n\nThank you for using this program\n"; // Again, be more creative
      }
      
      double GetRateOfPay()
      {	double payRate;
      	cout << "Please enter an employee's rate of pay \n";
      	cout << "Enter a -1 to quit ";
              cin >> payRate;
      	return payRate;
      }
      
      void OutputSalary (double salary)
      {	cout << "The employee's salary is: " << salary << endl;
      }
      
      void OutputTotals(int empCount, double salaryTotal)
      {	cout << "\n\nThe total number of employees processed was: " << empCount;
      	cout <<"\n\nThe total amount of money paid out in salaries was: " << salaryTotal;
      }
      
      double GetHoursWorked()
      {  double hoursWorked;
         cout << "Please enter the number of hours the employee worked ";
         cin >> hoursWorked;
         return hoursWorked;
      }
      
      double CalculateSalary(double rate, double hours)
      {	double regularSalary;
      	double overtimeSalary;
      	double fullSalary;
      	double overtimeRateOfPay
      	if (hours > REGULAR_HOURS)
      	{	regularSalary = REGULAR_HOURS * rate;
      		overtimeRateOfPay = rate * OVERTIME_ADJUSTMENT;
      		overtimeSalary = (hours - REGULAR_HOURS) *   overtimeRateOfPay; 
      		fullSalary = regularSalary + overtimeSalary;
      	}
      	else
      	{ 	fullSalary = hours * rate;
      	}
      	return fullSalary;
      }
      
      void ProcessSalaries(int& employeeCount, double& totalSalaries)
      {	  double rateOfPay;
      	  double overtimeRateOfPay;
      	  double regularSalary;
      	  double overtimeSalary;
      	  double fullSalary;
      	  double hoursWorked;  // can be a fraction of an hour
      	  
      	  employeeCount = 0;  // initialize the counter parameter to 0
      	  totalSalaries = 0;	  // initialize the salary total parameter to 0
      	  rateOfPay = GetRateOfPay();
      	  while (rateOfPay >= 0)
      	  {	hoursWorked = GetHoursWorked();
      	 	fullSalary = CalculateSalary(rateOfPay, hoursWorked);
      		OutputSalary(fullSalary);
      		employeeCount++;
      		totalSalaries += fullSalary; 
      		rateOfPay = GetRateOfPay();
      	  }
      }
      
      Exercise: Modify the 'main' found in Part A of this section so that the 'for' loop is moved out of 'main'.
      *********************

      C++ comes with a collection of pre-defined functions – used for everything from mathematical calculations to clearing the screen. These are declared in various '.h' files. In order to use these functions, one must know the name of the function, the number and order of the parameters, the return type, and what '.h' files to 'include' along with 'iostream.h'. You should check the on-line help for your compiler and any manuals you have access to. In the example code linked to this section in the html version of this document, you will find a program that uses pre-defined functions to clear the screen and wait for a user to hit the 'Enter' key.

      This ends the present discussion of functional decomposition and C++ functions. We will continue to use functions extensively in the coming chapters but functional decomposition will take a back seat to a new way of handling problem complexity discussed in the next chapter.


      Topics Covered in the "Essentials of C++"
      Functions

      Code Examples Involving Basic Function Declarations

      Top of Section Main Menu Next Chapter