Classes not being Inherited and help with virtual Functions?

Im trying to make 4 classes ( 1 base and 3 derived classes) for different types of Workers for a project.

Here's what it looks like when it runs:

Walter made 0
made 2000
made 2403.85
made 2692.31
___________________________________________
Walter made 0
made 0
made 0
made 0

None of the getName() functions work even though I know I inherited them properly. Also, what am I doing wrong with the compute_pay function in worker?
I know your supposed to use virtual functions but I just don't seem to get it.

For Comparison, heres what I want it to print out when it is working. Nothing is wrong with the worker.cpp,worker.h or driver.cpp


Walter made 0
Horatio made 2000
Sally made 2403.85
Nico made 2692.31
___________________________________________
Walter made 0
Horatio made 2000
Sally made 2403.85
Nico made 2692.31


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#ifndef WORKER_H
#define WORKER_H

#include<string>
#include<cstdio>
#include<iostream>

using namespace std;

class Worker
{
 public:
   Worker();
   Worker(string, int, string, int);
   double compute_pay() const;
   string getName() const;
   int getCompID() const;
   string getDepartment() const;
   int getSocialSecurityNumber() const;
 private:
   string name;
   int compid;
   string dept;
   int ssnum;
};
       
#endif 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include "Worker.h"

Worker::Worker()
{}


Worker::Worker(string name, int compid, string dept, int ssnum)
{
  this->name = name;
  this->compid = compid;
  this->dept = dept;
  this->ssnum =ssnum;
}


double Worker::compute_pay() const
{
  return 0.0;
}


string Worker::getName() const
{
  return name;
}

int Worker::getCompID() const
{
  return compid;    
}    

string Worker::getDepartment() const
{
  return dept;
}       

int Worker::getSocialSecurityNumber() const
{
  return ssnum;
} 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#ifndef HOURLYWORKER_H
#define HOURLYWORKER_H

#include <string>
#include <iostream>
#include <cstdio>
#include "Worker.h"

using namespace std;

class HourlyWorker : public Worker

/*
An HourlyWorker represents the specific case of a person who is compensated for
his/her work based on the amount of time (measured in hours) devoted to a work activity
multiplied by the hourly rate of pay (measured in dollars per hour).
For the purposes of this assignment we will compute the weekly pay amount as Weekly
Pay = Hours * HourlyPayRate
*/
{

public:
	HourlyWorker();
	//HourlyWorker(string, int, string, int,int,double,double);
		HourlyWorker(string, int, string, int,int,double,double);
	int getHoursWorked() const;
	float getHourlyPayRate() const;
	virtual double compute_pay() const;



private:
    int hoursWorked;
   float hourlyPayRate;
   double weeklyPay;
 
};

#endif 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "HourlyWorker.h"
#include "Worker.h"

HourlyWorker::HourlyWorker()
{
	
}

 
HourlyWorker::HourlyWorker(string name, int compid, string dept, int ssnum, int time, double rate, double getPay) 
{
  hoursWorked = time;
  hourlyPayRate = rate;
  weeklyPay = (hourlyPayRate * hoursWorked);
}


//Accessor Functions
int HourlyWorker::getHoursWorked() const
{
  return hoursWorked;    
}    

float HourlyWorker::getHourlyPayRate() const
{
  return hourlyPayRate;    
}    

double HourlyWorker::compute_pay() const
{
	return weeklyPay;
}

//float HourlyWorker::getPay(int,float) const
//{
//  return getPay;   
//}    


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#ifndef SALARIEDWORKER_H
#define SALARIEDWORKER_H

#include<string>
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include "Worker.h"


using namespace std;

class SalariedWorker: public Worker


/*A SalariedWorker is a worker that is paid a fixed annual amount known as a salary.
Depending on the payroll system used by an organization, a salaried worker is paid
periodically on a weekly, bi-monthly, or other basis. For purposes of this assignment, we
will compute the weekly pay amount as Weekly Pay = AnnualSalary / 52 . 
*/


{
 public:
 	
 	SalariedWorker();
 	SalariedWorker(string, int, string, int, double);
	virtual double compute_pay() const;
  
 private:
	
	double annualSalary; 
	double weeklyPay;
 

 
 
};
#endif 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include "SalariedWorker.h"
#include "Worker.h"


SalariedWorker::SalariedWorker()
{
	
}

SalariedWorker::SalariedWorker(string name, int compid, string dept, int ssnum, double annualSalary)
{


weeklyPay = annualSalary/52;

	
}


double SalariedWorker::compute_pay() const
{
	return weeklyPay;
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#ifndef MANAGER_H
#define MANAGER_H

#include<string>
#include<cstdio>
#include<iostream>

#include "Worker.h"
#include "SalariedWorker.h"


using namespace std;


class Manager : public SalariedWorker

/*
A Manager is a specific case of a salaried worker that manages a department. A
manager receives a salary, and may also receive a large monetary bonus at the end
of the year if the manager’s department meets or exceeds certain departmental
goals. For purposes of this assignment, we will compute the weekly pay amount as
Weekly Pay = (AnnualSalary + Bonus from last year) / 52.
*/

{
 public:
 	
Manager();
Manager(string, int, string, int, double,double);
double getBonus();
	virtual double compute_pay() const;

   
 private:
 	double bonus;
 	double weeklyPay;
 
};
       
#endif 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include "SalariedWorker.h"
#include "Manager.h"
#include "Worker.h"


Manager::Manager()
{
	
}

Manager::Manager(string name, int compid, string dept, int ssnum, double annualSalary, double bonus)
{

weeklyPay = (annualSalary + bonus)/52;
	
}





double Manager::compute_pay() const
{
	return weeklyPay;
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//THIS IS THE DRIVER!
#include "Worker.h"
#include "HourlyWorker.h"
#include "SalariedWorker.h"
#include "Manager.h"

using namespace std;

int main()

{
  Worker         w("Walter", 70113, "sales", 123456789);
  HourlyWorker   h("Horatio", 70114, "accounting", 999999999,50.0, 40.0, 10.0);
  SalariedWorker s("Sally", 72000, "IT", 333333333, 125000.00);
  Manager        m("Nico", 71111, "marketing", 414414141, 125000.00, 15000.00);
  
  cout << endl;
  cout << w.getName() << " made " << w.compute_pay() << endl;
  cout << h.getName() << " made " << h.compute_pay() << endl;
  cout << s.getName() << " made " << s.compute_pay() << endl;
  cout << m.getName() << " made " << m.compute_pay() << endl;
  cout << endl;


 
  Worker workers[] = {w,h,s,m};
  for (int i = 0; i < 4; i++)
  cout << workers[i].getName() << " made " << workers[i].compute_pay() << endl;


  cout << endl;

  system("pause");
  return 0;    
    
    
}    
Last edited on
Your "compute_pay" function needs to be declared virtual in your base class, that way all the derived classes (SalariedWorker, HourlyWorker, ...) can get the virtual behavior thru pointers/references of the base.

Line 26 creates an array of "Workers", that is objects, not references/pointers so the resulting passing of "w, h, s, m" does what's called "slicing" it removes any derived-class-related information when creating these new, empty Worker objects, that's why you're getting outputs of 0 and empty strings.

Try making Worker::compute_pay() virtual, and makers "workers[]" Be an array of pointers, then line 27's for loop should work differently ;).
Also, one should not be allowed to instantiate the base class. The base class should contain the interface for the other classes to use, do this by making one or all of the functions pure virtual, or make all the constructors protected.

So, either come up with a generic name for the base class, or invent another name for the class that Walter's object belongs to. Labourer maybe? With Worker as the base class.

Make sure that the constructor's initialise all the class and base class members, by using a member initializer list with calls to the base class constructor.

If you already have another constructor, and you default constructor does nothing, don't bother declaring or defining it. Constructors can be defaulted or deleted explicitly, and the compiler will generate implicit ones if you don't.

The names of some of your functions are misleading. You have getBonus which calls compute_pay which returns weeklyPay. Would it not be easier to have getBonus return weeklyPay ? And mark it const. In my mind at least, an accessor function should just return a member value, if it does something else, like a calculation then name it as such.

If you make your workers array a std::vector of pointers to the base class, you can have polymorphism. So you would push_back pointers to the derived class objects. Being a vector, you can interrogate it's size, or not even worry about it's size, and use a ranged base for loop, to iterate through the whole container.

Avoid having using namespace std;any where, put std:: before each std thing, it;s the best way and all the experts do that.

Provide names for the function parameters in your function declarations (not just a type), make them the same what is in the function definition. This is not mandatory, just better if you do.

Always use braces even when there is only 1 statement in a loop or if or whatever. It will save you one day when you add more code.

Always indent your code properly, your IDE should do it for you, before or after the fact. This aids understanding and helps spot errors. There are tools like clang-format that will do this - if you are a non-IDE warrior :+) Thanks to ne555 to remind me to remind others about this.

I didn't compile your code, so not sure on how well you do this (you might be fine), but set your compiler warnings to their highest, and don't ignore them if you get any.

There you go, some stuff to work on :+)

Hey Thanks Magnus pi, it's now printing the proper values but the getName's still arent working properly?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 Worker         w("Walter", 70113, "sales", 123456789);
  HourlyWorker   h("Horatio", 70114, "accounting", 999999999,50.0, 40.0, 10.0);
  SalariedWorker s("Sally", 72000, "IT", 333333333, 125000.00);
  Manager        m("Nico", 71111, "marketing", 414414141, 125000.00, 15000.00);
  
  cout << endl;
  cout << w.getName() << " made " << w.compute_pay() << endl;
  cout << h.getName() << " made " << h.compute_pay() << endl;
  cout << s.getName() << " made " << s.compute_pay() << endl;
  cout << m.getName() << " made " << m.compute_pay() << endl;
  cout << endl;


 
  Worker* workers[] = {&w,&h,&s,&m};
  for (int i = 0; i < 4; i++)
  cout << workers[i]->getName() << " made " << workers[i]->compute_pay() << endl;


  cout << endl;

  system("pause");
  return 0;    


Here's what I get when it prints out.


Walter made 0
Horatio made 2000
Sally made 2403.85
Nico made 2692.31
___________________________________________
Walter made 0
made 2000
made 2403.85
made 2692.31
16
17
18
19
double Worker::compute_pay() const
{
  return 0.0;
}


Did you make the changes in your other files, not just in main() ?
Well besides the main() , all I did was change the base class to virtual in the Worker.h?
virtual double compute_pay() const;

Forgive me if I'm slow on the uptake its been a long day and I'm getting tired (Been working on Calc and Linux homework from 7am, this is the last thing on my to do list).

Forgive me if I'm slow on the uptake its been a long day and I'm getting tired (Been working on Calc and Linux homework from 7am, this is the last thing on my to do list).


No worries :+) tomorrow is another day, sometimes it is better to approach these things with a clear head :+)

There were a bunch of suggestions I made, so maybe you can have a closer look at those? Especially what I said about the base class.

Any way I hope it all goes well :+)
Im still not understanding it. I set some setters in the worker but The getNames still arent working. Anyone else can point me in the right direction?
My problem with the code is that you are instantiating the base class, IMO one shouldn't do that, so that is why I am suggesting about changing the base class:

1
2
3
4
5
6
class Employee;    // The base class, with virtual functions that apply to all the classes
                            // don't instantiate this class
class Worker : public Employee;  // Worker is now a little too generic, is there a better description?
class Hourly : public Worker;  // leave the base class name out of he derived class name
class Salaried : public Employee;
class Manager : public Salaried;



If things aren't working it's hard to know if we can't see the new code.

Anyone else can point me in the right direction?


Maybe I didn't explain so well the first times, perhaps I didn't explain why I gave the advice I gave, but it is slightly off putting to be construed as being dismissed. Maybe you didn't mean it that way :+)

I hope things are clearer now.
Lol I got it Thanks IdeasMan, I solved it.


On another note, It had to be named worker as that was what the name of the project. I was given the worker and driver files and had to build the sub classes around them.

I also took your advice from earlier on everything except the using namespace std as even though it's less professional, Im too lazy to type std:: on every standard thing. Oh and my teacher left it as an array so I didn't bother changing it unless explicity told to change it to a vector.

Last edited on
Im too lazy to type std:: on every standard thing.


Find & Replace :+) after the fact, otherwise it's amazing how quickly one gets used to it.

But I didn't mention this just to cajole you into doing more typing. There are real and bad implications from bringing in the entire std namespace, the main one is name conflicts - which the very concept of namespaces is supposed to solve, and are ruined by that using declaration. There are lots of ordinary variable names in std, that one might naively try to use (for function names as well), and cause problems because the compiler uses the name in std instead. There have been lots of beginners and even reasonably advanced people on this forum that have had that exact problem.

It's a bit like addressing a msg to your girlfriend, but instead of it going to her, it goes to some other old lady in your town - one that has the same first name .

Ideally, one should put their own code into their own namespace, instead of being in the default global namespace.

Well the best thing is that you r problem is now solved :+)

Regards
Topic archived. No new replies allowed.