surrealtrauma said:
Thank for your help.
// any reason why you don't use a std::string?
since I havn't learn about std::string.
Funny, you already have used it !
The second parameter to 'input_data' is of type string and so
is the member variable 'emp_no'
i have very poor skill with using c++, i am just doing the hw.
No problem. We all started sometimes.
[snip code]
WHen I compare your code with your teachers code then I see a pattern:
You simply moved all functions in the class. Well, that's not entirely wrong,
but in your case you made an oversight:
An object of class employee is responsible for *one* employee.
The functions your teacher gave you however deal with a whole
array of employees.
Now when you move such a function into the class, you should stick
with: deals with just one object. That also means that you still will
have those stand alone (non class) functions that have to deal with
the whole array of objects. But this time the functionality is balanced
differently.
Example:
Your teacher gave you:
// display information of all employees and finally display the average
// hours worked among all employees
void display_data(employee_record employee_info[], double average_hours_worked)
{
double sum = 0;
for (int i=0; i<no_of_employees; i++) // loop used to produce
// all employees' information
{
cout << endl;
cout << "Employee Name: " << employee_info
.emp_name << endl;
cout << "Hours Worked: " << employee_info.hours_worked << endl;
cout << "Employee Salary: " << employee_info.salary << endl;
}
cout << endl;
cout << "Average hours worked for " << no_of_employees << " employees: "
<< average_hours_worked << endl;
}
You now need to analyze this function and ask youself a question: Which of the above
is really the responsibility of one single employee object, and which of the above
is just there because that function deals with a whole array of objects.
If you do this, it turns out, that outputting the employee data (such as name, hours worked,
salary) can be seen as the reponsibility of one employee object. It is like you give
an order to one employee: 'Hey, Bob. Give me your data!'. Thus you will want to add
a function to your class, that does exactly that: output the employees data. You will
use that by eg.
void display_data(employee_record employee_info[], double average_hours_worked)
{
double sum = 0;
for (int i=0; i<no_of_employees; i++) // loop used to produce
// all employees' information
{
employee_info.display_data();
}
cout << endl;
cout << "Average hours worked for " << no_of_employees << " employees: "
<< average_hours_worked << endl;
}
See. The above function no longer needs to know, that an employee has a name, knows how
many hours he/she has worked etc. The function simply delegates to the amployee object
itself to output its data. And it is up to the employee object to know what data can
be output:
class employee
{
....
void display_data();
....
};
void employee::display_data()
{
cout << "Employee Name: " << emp_name << endl;
cout << "Hours Worked: " << hours_worked << endl;
cout << "Employee Salary: " << salary << endl;
}
This is where object orientation kicks in. Each object is reponsible for itself.
It is not the job of the stand alone display_data function, to know that an employee
has a name, a number and a salary. It just tells the object to output itself.
That doesn't mean that it may not be a good idea to have employee member functions
to allow for getting at the name, salary and so on. The problem is this: Now the
functionality of which data members get output has moved into the employee class.
That may be a good thing. But who is telling you, that you want exactly that information
in the output? For a different purpose you might want a different output, but the
employee object cannot know this. It is out of its scope to know this, because it
may depent entirely on what type of listing you are creating: An output for just
having all employees with their employee number looks different from a listing which
is used to pay those employees.
So what I am trying to get at is: When you move functionality around, you need to think
about which functionality belongs where. Eg. a function that calculates the total salary
based on hours worked and the hourly rate is definitily a member of the employee
class. So make it one:
class employee
{
....
void CalculateSalery();
void display_data();
....
};
void employee::CalculateSalery()
{
salary = hours_worked * hourly_rate;
}
and you use that function eg. in
// calculate the employees' salary and average hours worked among all
// employees
void process_data(employee_record employee_info[], double &average_hours_worked)
{
double sum = 0;
for (int i=0; i<no_of_employees; i++) // loop used to calculate
// salary for all employees and
{
employee_info.CalulateSalary();
sum = sum + employee_info.hours_worked;
}
average_hours_worked = sum / no_of_employees; // calculate the average
// hours worked by employees
}
Again: Note the slight shift in reponsibility. It is no longer the job of
this function process_data to calulate the salary for each employee. Instead
this functionality is shifted to the employee object itself. There might
be different ways to calculate that salary, there may be addons, different taxes
to pay etc. But it is not the job if this function to account for that - the
employee itself should do that.
What about the hours worked among all employees. Can a single employee know how
to do that? No. A single employee object knows about, well, a single employee
object. But to calculate that average, *all* employees need to participate. Thus
this functionality cannot be shifted into the employee class. It is simply not
its responsibility to calculate that average. Thus this functionality will stay
in function process_data(). But of course this function will need some ways to
get at the data which allows it to calculate that average. In particular it
will need a function which allows it to ask each employee for the hours he/she
worked:
// calculate the employees' salary and average hours worked among all
// employees
void process_data(employee_record employee_info[], double &average_hours_worked)
{
double sum = 0;
for (int i=0; i<no_of_employees; i++) // loop used to calculate
// salary for all employees and
{
employee_info.CalulateSalary();
sum = sum + employee_info.GetHoursWorked();
}
average_hours_worked = sum / no_of_employees; // calculate the average
// hours worked by employees
}
And employee, of course will need to implement that function:
class employee
{
....
int GetHoursWorked();
void CalculateSalery();
void display_data();
....
};
coid employee::GetHoursWorked()
{
return hours_worked;
}
void employee::CalculateSalery()
{
salary = hours_worked * hourly_rate;
}
Now, what is so important about that shift of functionality?
Well. We have freed the function process_data of the knowlegde of how
and where the information 'hours_worked' is stored. It simply doesn't
care any longer. All this function does is ask the employee object:
"Hey, Buddy. How many hours have you worked?" And the employee object
responds with the correct figure. All that is important for process_data
is to get that number. It is no longer important for process_data how
the imployee object came up with that number. The employee object could,
have looked it up in a data base, it could have calculated that number,
it could have consulted some registering clock to come up with that number,
etc. All of that is no longer important to process_data. It asks the
employee object for that number, and it gets it from the employee object.
That is an important point in object oriented programming: To put
functionality where it belongs in order to free the rest of the
program to know the details how a specific functionality works.