|
Table of Contents
|
|
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:
- The function 'ProcessSalaries' takes the place of 'CalculateSalaries
' in 'main'.
- We have a new function called 'OutputTotals' that outputs the total
number of employees processed and the total paid out in salaries.
- 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
|
|