Link to home
Start Free TrialLog in
Avatar of imlearning
imlearning

asked on

Casting from derived class

I have a base Employee class and three derived class , Salary, Hourly, and PieceWork

I have a container class
class Employees{
 
   private:
      Employee *all[MAX];
      int EmployeeCount;
      void qs_lname(int left, int right);
   public:
      Employees():EmployeeCount(0){}
      void add(Employee &e);
      void remove(Employee &e);
      int search(char* l);
      void quickSort(){qs_lname(0,EmployeeCount-1);}
      void calcAllGross(void);
      void calcAllNet(void);
      void printByGroups(void);
     
};

so im working on printByGroups which prints a report grouped by the derived types

and I need to do this

subTotalHours=all[0]->getHours(); // but getHours is a member of the derived Hourly class
   error C2039: 'getHours' : is not a member of 'Employee'

how do I cast so that i can get to that method
Avatar of jkr
jkr
Flag of Germany image

Since you know that only the derived classes have that method, cast the pointer accordingly, e.g.

subTotalHours=((Hourly*)all[0])->getHours(); // but getHours is a member of the derived Hourly class
 

Avatar of imlearning
imlearning

ASKER

hi jkr

i tried doing just that
float subTotalHours=((Hourly*)all[0])->getHours();

and i get
error C2059: syntax error : ')'
syntax error : identifier 'Hourly'
error C2061: syntax error : identifier 'Hourly'
error C2065: 'Hourly' : undeclared identifier

Let me explain how I have my project setup

I have employee.h // Has Employee(base)class  and Employees (container) Class
and hourly.h // #include "employee.h"
      salary.h// #include "employee.h"
      pieceWork.h // #include "employee.h"
and my payroll.cpp (main)
     #include "employee.h"
     #include "hourly.h"
     #include "salary.h"
     #include "piecework.h"
is that the problem ? ( im new with header files)

thanks

also here is my main

   Employee *test = new Hourly("Doe","John",27.00,46.50,50);
   Employee *test2 = new PieceWork("Whittle","Ed",11.50,25.50,0);
   Employee *test3 = new PieceWork("Marion","Louise",13,40,100);
   Employee *test4 = new Salary("Prentiss","Paula",15.75*50.5,124);
   Employee *test5 = new Hourly("Davidson","Carl",8.75,38,15);
   
   Employees Company;

   Company.add(*test);
   Company.add(*test2);
   Company.add(*test3);
   Company.add(*test4);
   Company.add(*test5);
No, that should work. It is however hard to diagnose what'S going wrong without seeing more of the code.
You add the function getHours(); in the Employee class.
for example
class Employee
{
..
..
..
public:
int getHours()
{
}
};

heres my code, thanksfor your time jkr
=======================================================
class Employee {
  protected:
     enum EmployeeType {salaried,hourly,piecework}; // derived types
  private:
     char *lname;
     char *fname;
     float deffered;
     float gross;
     float net;
     float fedTax;
     float stateTax;
     float ssiTax;
     float calcFed(void) {return (gross-deffered)*FEDTAXRATE;}
     float calcState(void){return (fedTax * STATETAXRATE);}
     float calcSSI(void){return (gross-deffered)*SSITAXRATE;}
  public:
     Employee(const char*last="",const char* first="",float deff=0.0)
     :lname(NULL), fname(NULL),deffered(deff),gross(0), net(0), fedTax(0), stateTax(0), ssiTax(0)
     {
        int len = strlen(last);
        lname = new char[len+1];
        strcpy(lname, last);
        len = strlen(first);
        fname = new char[len+1];
        strcpy(fname, first);

      }
     ~Employee()//destruct
     {
        delete [] fname;
        delete [] lname;
     }
     char* getLastName(void)const{return this->lname;}
     char* getFirstName(void)const{return fname;}
     const float getDeffered(void)const{return deffered;}
     const float getGross(void)const{return gross;}
     const float getNet(void)const{return net;}
     const float getFedTax(void)const{return fedTax;}
     const float getStateTax(void)const{return stateTax;}
     const float getSSITax(void)const{return ssiTax;}
     
     void setLastName(const char * last){ int len =strlen(last);lname = new char[len+1];strcpy(lname, last);}
     void setFirstName(const char * first){int len =strlen(first);fname = new char[len+1];strcpy(fname, first);}
     void setDeffered(const float def){deffered=def;}
     void setGross(const float f){gross=f;}
     void calcNet(void);
 
     virtual void calcGross(void)=0;
     virtual EmployeeType GetType() const = 0;
   
};
void Employee::calcNet(void)
{
 
  if(this->getGross()>0)
  { // protect the data
     this->fedTax = calcFed();
     this->stateTax = calcState();
     this->ssiTax = calcSSI();
     this->net = gross-(fedTax+stateTax+ssiTax+deffered);
  }
  else
  { cout<<"\nGross is less than Zero";}
}
===================================================
class Employees{
 
   private:
      Employee *all[MAX];
      int EmployeeCount;
      void qs_lname(int left, int right);
   public:
      Employees():EmployeeCount(0){}
      void add(Employee &e);
      void remove(Employee &e);
      int search(char* l);
      void quickSort(){qs_lname(0,EmployeeCount-1);}
      void calcAllGross(void);
      void calcAllNet(void);
      void printByGroups(void);
     
};

void Employees::calcAllGross(void)
{
   for(int i =0;i<EmployeeCount;i++)
      all[i]->calcGross();
}


void Employees::qs_lname(int left, int right)
{
   int i, j;
   const char *x; // temp string
   i = left; j = right;
   x = all[(left+right)/2]->getLastName(); // sorting by last name
   do
   {
      while((strcmp(all[i]->getLastName(),x) < 0) && (i < right))i++;
      while((strcmp(all[j]->getLastName(),x) > 0) && (j > left)) j--;
      if(i <= j)
      { // swap
         Employee *temp =all[i];
         all[i] = all[j];
         all[j] = temp;
         i++; j--;
     }
   } while(i <= j);
   if(left < j) qs_lname(left, j);
   if(i < right) qs_lname(i, right);
}
void Employees::printByGroups(void)
{

   float subTotalHours=((Hourly*)all[0])->getHours();
   

}


void Employees:: calcAllNet(void)
{
   for(int i =0;i<EmployeeCount;i++)
      all[i]->calcNet();

}
void Employees::add(Employee &e)
{
   if(EmployeeCount<MAX)
   {  int found=search(e.getFirstName()); // search first if employee exists
      if(found==-1)
      {
         all[EmployeeCount]=&e;
         EmployeeCount++;
         return;
       }
       else
       {
          cout<<"\nEmployee Already Exist: not added: \n";
          return;
       }
    }
    else
       cout<<"\n Error :Container Is Full:\n";
}
int Employees::search(char* l)
{
   for(int i=0;i<EmployeeCount;i++)
   {
      if(strcmp(l, all[i]->getLastName())==0)
         return i;
   }
   return-1;
}
void Employees::remove(Employee &e)
{
   int found=search(e.getLastName());
   if (found >= 0)
   {   Employee *erase=0; // Null Pointer
       all[found]=all[EmployeeCount-1];//set found to last pointer
       all[EmployeeCount-1]=erase;//set last pointer to null
       --EmployeeCount;
       quickSort();          
   }
}
==============================================
class Hourly : public  Employee{

   private:
      float hours;
      float payrate;
   public:
      Hourly(char * last="",char *first="",float pr=0,float hr=0,float deff=0):
         hours(hr>0?hr:0),payrate(pr>0?pr:0),Employee(last,first,deff){}
      Hourly(Hourly &h):
         hours(h.getHours()),payrate(h.getPayRate()),Employee(h.getLastName(),h.getFirstName(),h.getDeffered()){}

      void setHours(const float f){(f>0)?hours=f:hours=0;}
      float getHours(void)const{return hours;}
      void setPayRate(const float f){(f>0)?payrate=f:payrate=0;}
      float getPayRate(void)const{return payrate;}

      void calcGross()
      {
         if(hours <= 40)
          this->setGross(hours * payrate);
         else
          this->setGross( 40 * payrate + (hours-40)* 1.5 * payrate);
      }
      virtual EmployeeType GetType() const { return hourly;}
};
================================================
If you have the pointer of a parent class, then you cannot access the functions of the derived class. If all the derived classes are having getHours function, then declare the function in parent class ie Employee class as i have shown above and implement the function in all the derived classes. the compiler will call the function of the class to which the object is pointing at run time.
The error is because you have Employee class pointer ie test,test2, test3, test4 . when you call test->getHours() compiler cannot resolve the function name because its not defined in the Employee class.

hope this could help you
What file is

void Employees::printByGroups(void)
{

   float subTotalHours=((Hourly*)all[0])->getHours();
   

}

?

You will have to add

#include "hourly.h"

to that one also.
per the assignment spec  getHours can't be a member of Employee


I tried adding #include"hourly.h" to "employee.h"
error C2440: 'initializing' : cannot convert from 'Hourly *' to 'Employee *'
error C2440: 'initializing' : cannot convert from 'Hourly *' to 'Employee *'
error C2501: 'Hourly::EmployeeType' : missing storage-class or type specifiers
hourly.h(2): error C2504: 'Employee' : base class undefined

Should I put all the derived classes and base class in one file ?
Or should i change my container data member ?? or is that not the problem ?

thanks guys
I also tried putting all the code into one cpp file and i get
test.cpp(139): error C2065: 'Hourly' : undeclared identifier
test.cpp(259): error C2061: syntax error : identifier 'Hourly'


is it because of the way my container is holding the data ?
Put the classes/implementation to the following files:

// employee.h
#ifndef EMPLOYEE_H
#define EMPLOYEE_H

class Employee
{
    ...
      friend class Employees;  
};

#endif
// end of employee.h

// employees.h
#ifndef EMPLOYEES_H
#define EMPLOYEES_H

class Employees
{
    ...
};

#endif
// end of employees.h


// hourly.h
#ifndef HOURLY_H
#define HOURLY_H

#include "employee.h"

class Hourly : public Employee
{
    ...
};
#endif
// end of hourly.h


put all your member implementation to according employee.cpp, employees.cpp, hourly.cpp .

All cpp can include all needed header files.

Some remarks to the class design:

if you are not allowed to declare friend classes, you have to provide public get/set functions for class Employee.

Hourly doesn't seem a good derivation of class Employee. A public derivation is a so-called "IS A" relation, i.e. an 'Hourly' *is an* 'Employee' in your case. That hardly is a good design. If I am right that is the reason why you got problems when managing 'Hourly' objects by means of an array of employee pointers. I would say class Employee should 'have' an Hourly object as member - or use a pointer if not all employees have a 'Hourly' extension.

If you post the spec we can give you more advice.

Regards, Alex
Hi alex,
I dont know if you remember  but you helped me build the Employee and Employees class. And now our assignment was to derive three classes(salary,hourly,piecework) from the Employee class, and make the Employee class abstract by making calcGross a purevirtual service.

So since i had to do this
Employee *test = new Hourly("Doe","John",27.00,46.50,50);
I had to change my container(Employees class) right ? becuase the old one did this

Employees(void) : allEmployees(NULL), EmployeeCount(0), EmployeeSize(0)
     {allEmployees= new Employee[EmployeeSize];}
 // and i was getting a compile error saying i cant instance a abstract type

So I changed my container to hold an array of pointers to Employees only,
   Employee *all[MAX];<--is it ok that i dont dynamically allocate w/ new
   int EmployeeCount;
public:
    Employees():EmployeeCount(0){} <-is it ok that i dont dynamically allocate w/new

Was that the right thing to do ?

I will work on creating the header files in the meantime, it doesnt help that this project is due today(5:30pm pacific time), He only gave us a week to do it, but i thought it would be a cake walk since i got 110% on the last project you helped me with

thanks alex
ps for reference my old ID was dreaminbinay
>>>> And now our assignment was to derive three classes(salary,hourly,piecework)

As I told you above, a public derivation is called an "is a" relation. So, hourly, salary, piecework are very poor names for derivations of class employee when looking on them with an OO kind of view... But never mind. The above at least gets some sense...

>>>> So I changed my container to hold an array of pointers to Employees only,

Yes, that is good. You need access the baseclass pointers virtually to get access to the *real* objects.

>>>> is it ok that i dont dynamically allocate w/ new

That depends on your requirements. If you can determine a suitable maximum size of the number of employees, it is ok. If your requirement is to be able to manage a dynamical count of employees you should turn to the Employees class we already made dynamically last time.

>>>> per the assignment spec  getHours can't be a member of Employee

That is ok, cause you have three cases of employees, you shouldn't have a virtual function in the baseclass that is only valid for one specialization. The key issue is that you should *drive* the application by iterating the employees array and call the virtual function calcGross. After calling you are in the context of the derived class waht means that in Hourly::calcGross you can call Hourly::getHourly(...)  without problems and in Salary::calcGross you can call Salary::getMonthlySalary(...), and so on... Do you get the point?

Regards, Alex


alex
-- I set up the header files per your spec

--when im calcingGross i do that in the container
void Employees::calcAllGross(void)
{
   for(int i =0;i<EmployeeCount;i++)
      all[i]->calcGross();
}
and that works fine


now im lost again....

per the assignment spec we have to produce a report method in the Employees class that totals and subtotals the derived classes.

so  making this method
void Employees::printByGroups(void)
{  

   for(int i=0 ; i<EmployeeCount ; i++)
   {
      if(all[i]->GetType()==1) //this is a hourly derived type
      {  //print employee line to file and subTotals for Hourly go here
         float subTotalHours=((Hourly*)all[0])->getHours(); <-- trying to cast up
      }
   }
}


is this the wrong approach ? thanks again for your time
>>>> if(all[i]->GetType()==1)

That is bad. Or let us say it is against virtuality that the baseclass or its container do know about all types (so I must admit that most report writers know about the kind of objects supposed to get printed).

To make it really good, you should sort the container on the type attribute. I think a bubble sort would do like

void Employees::sortTypes()
{
       for(int i=0 ; i<EmployeeCount ; i++)
         for(int j=i+1 ; j<EmployeeCount ; j++)
         {
               if(all[j]->GetType() < all[s]->GetType() ) //this is a hourly derived type
               {
                   Employee* pTemp = all[i];
                   all[i] = all[j];
                   all[j] = pTemp;
               }
        }
}

After doing so, the container was separated into groups.

You now can iterate again and if type changes you call a virtuelly defined 'printTotal' function to close the previous group (of course only if it isn't the very first group). The printTotal would print static defined members of the derived class which represent the total of all 'gross' values for that class. You have to fill these values in calcGross function. Then call 'printTitle' virtually what would print the title line(s) for the next group. For each element of that group call virtually 'printGros' which prints the statistics for one element of the container. Finally, call 'printTotal' for the last group (outside of the loop.)

void Employees::printReport()
{
     // check (EmployeeCount > 0)
     ...    
     // sort employees into groups
     ...
     // init last type to an unknown type, e. g. -1
     ...
     
     // iterate the sorted container
     for( ...
     {
         // check if type changed
         ...
         {
              // call PrintTotal for the previous element  (if exist)
              ...
              // call PrintTitle for the current element
              ...              
              // save last type to current type
              ...
         }
         // call PrintGross for the current element
     }
     // call PrintTotal for the last element in the container
     ...
}

Hope, it was understandable.

Regards, Alex
Alex I understand the sortType

so here is what my driver is doing

   Employee *test = new Hourly("Doe","John",27.00,46.50,50);
   Employee *test2 = new PieceWork("Whittle","Ed",11.50,25.50,0);
   Employee *test3 = new PieceWork("Marion","Louise",13,40,100);
   Employee *test4 = new Salary("Prentiss","Paula",15.75*50.5,124);
   Employee *test5 = new Hourly("Davidson","Carl",8.75,38,15);
   
   Employees Company;

   Company.add(*test);
   Company.add(*test2);
   Company.add(*test3);
   Company.add(*test4);
   Company.add(*test5);

   Company.calcAllGross();
   Company.calcAllNet();
   Company.sortTypes();

so now all of my pointers are sorted by types

now for the Employees::printReport()
my Report headers are this

Employee       Pay        Reg Hrs             Gross           Fed               SSI             Net
Name            Rate       Ovt Hrs              Pay             State             Defr             Pay
=======  ======     ======      ======       ======      ======       =====

and per assignment spec I need

1.) Each derived types to be grouped, and sorted by last name, and have subtotals for each group i.e subtotal all Hourly Employees  payRate, regHours,OvtHours ....

so im going to change the sortType to include sorting by last name

now when i get to here im not understanding the logic
void Employees::printReport()
{
     if (EmployeeCount > 0)
     ...    
     this.sorthType();
     ...
     // init last type to an unknown type, e. g. -1 <--- confused??
     ...
     
     for( ...
     {
         // check if type changed <--- how do i do this??
         ...
         {
              // call PrintTotal for the previous element  (if exist) <-- what is printTotal ?
              ...
              // call PrintTitle for the current element
              ...              
              // save last type to current type
              ...
         }
         // call PrintGross for the current element
     }
     // call PrintTotal for the last element in the container
     ...
}
thanks alex
also alex can you take a look at my add

void Employees::add(Employee &e)
{
   if(EmployeeCount<MAX)
   {  int found=search(e.getFirstName()); // search first if employee exists
      if(found==-1)
      {
         all[EmployeeCount]=&e; <<----- is this ok ????
         EmployeeCount++;
         return;
       }
       else
       {
          cout<<"\nEmployee Already Exist: not added: \n";
          return;
       }
    }
    else
       cout<<"\n Error :Container Is Full:\n";
}
>>>> so im going to change the sortType to include sorting by last name

Change the sorting condition to

              if(all[j]->GetType() < all[i]->GetType()  ||
                  (all[j]->GetType() == all[i]->GetType() && all[j]->GetName() < all[i]->GetName()  ) )

// init last type to an unknown type, e. g. -1 <--- confused??

e. g.

// employee.h

enum { no_type = -1, hourly, salary, piecework };


// employees.cpp

   ...
   int lasttype = no_type;   // that is done to get the title of the first group printed

>>>> // check if type changed <--- how do i do this??

Exactly, that is the corresponding part to the above:

     if (all[i]->getType() != lasttype)
     {
           all[i]->PrintTitle();   // pints the title of any new group including the very first
           ...

>>>> <-- what is printTotal ?

You are right it should be called PrintSubTotal. It is the sum line (the total for Gross Pay and Net Pay) for one group.

Regards, Alex

ASKER CERTIFIED SOLUTION
Avatar of itsmeandnobodyelse
itsmeandnobodyelse
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hey thanks alot alex ..

i got everything .. alot to take in for a newbie , but as i have said before you have taught me more in one of these post than ive learned all semester.

thanks again for your time and detailed posts