| |
Main Menu | Next Chapter |
| 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 |
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:
Given this design, the function declaration becomes:
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:
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:
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:
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,
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.
Code Examples Involving Basic Function Declarations
| |
Main Menu | Next Chapter |