Multiple Inheritance

 < Day Day Up > 



A class can inherit the functionality from more than one class which means it will have more than one base class. The act of inheriting the functionality from multiple classes is referred to as multiple inheritance. I will demonstrate multiple inheritance by creating a simple payroll application. Figure 13-14 gives the class diagram.

click to expand
Figure 13-14: Payroll Application Class Diagram

Referring to figure 13-14, the Person class is reused code from chapter 11. There are two abstract classes: Payable and Employee. Payable is abstract because it declares a pure virtual function named pay(). In fact, the only thing the Payable class does is declare this virtual function. In this regard, Payable is publishing an interface to which subclasses either must implement or let further subclasses implement.

The Employee class inherits from Person and Payable. So, an Employee is a Person and is a Payable. Because the Person class provides all the functionality of storing a person’s name and other such information the Employee class need not worry about replicating that functionality. Since an Employee is a Person, any class that inherits from Employee in the future will also be a Person and inherit the functionality of Person.

The relationship between Employee and Payable is somewhat different than that between Employee and Person. This is due to the pay() function being a pure virtual function. The Employee class must either implement pay() or not. If it does not, which is the case here, the Employee class becomes abstract, meaning there can be no instances of Employee and the pay() function must be implemented by classes derived from Employee.

The HourlyEmployee and SalariedEmployee classes inherit from Employee. This makes both of them an Employee, a Person, and a Payable. Both HourlyEmployee and SalariedEmployee have all the functionality of Employee and Person, however, since the pay() function was not implemented in the Employee class they each must declare and define what the pay() function means to them. The assumption made here is that an HourlyEmployee’s pay will be calculated differently from a SalariedEmployee’s pay.

In addition to multiple inheritance this simple payroll application demonstrates virtual function overriding and dynamic polymorphic behavior. Let us take a closer look at this application starting with the Payable class whose code is given in example 13.21.

Listing 13.21: payable.h

start example
 1   #ifndef PAYABLE_H 2   #define PAYABLE_H 3 4   class Payable { 5      public: 6         virtual float pay() = 0; 7   }; 8   #endif
end example

The Payable class simply declares the pure virtual function pay(). The code for the Employee class is given in Example 13.22.

Listing 13.22: employee.h

start example
  1  #ifndef EMPLOYEE_H  2  #define EMPLOYEE_H  3  #include "person.h"  4  #include "payable.h"  5  6  class Employee : public Person, public Payable{  7      public:  8         Employee(char* f_name = "Brand", char* m_name = "New", char* l_name = "Employee",  9                  char sex = 'M', int age = 18); 10         virtual ~Employee();   11         int getEmployeeNumber();   12         void setEmployeeNumber(int number);   13         int getEmployeeCount();   14 15      private:   16         int employee_number;   17         static int employee_count;   18  }; 19 20  #endif
end example

Line 6 of example 13.22 begins the Employee class declaration. Notice that additional base classes are separated by a comma. The Employee class implementation code is given in example 12.23.

Listing 13.23: employee.cpp

start example
  1  #include "person.h"  2  #include "employee.h"  3  4  5  int Employee::employee_count = 0;  6  7  Employee::Employee(char* f_name, char* m_name, char* l_name, char sex,   8                      int age):Person(f_name, m_name, l_name, sex, age){  9           employee_number = ++employee_count; 10  } 11 12  Employee::~Employee(){} 13 14  int Employee::getEmployeeNumber(){return employee_number;} 15 16  void Employee::setEmployeeNumber(int number){ 17       employee_number = number; 18  } 19 20  int Employee::getEmployeeCount(){ return employee_count;}
end example

You may be surprised at the small size of this file. Since most of the work is done in the Person class there is little for the Employee class to do except implement the three public functions getEmployeeNumber(), setEmployeeNumber() and getEmployeeCount(). The Employee class does not implement the pay() function; that will be left to the derived classes HourlyEmployee and SalariedEmployee. The class declarations for each of these files is given in examples 13.24 and 13.25.

Listing 13.24: hourlyemployee.h

start example
  1  #ifndef HOURLY_EMPLOYEE_H  2  #define HOURLY_EMPLOYEE_H  3  #include "employee.h"  4  5  class HourlyEmployee : public Employee{  6      public:  7          HourlyEmployee(char* f_name = "Brand", char* m_name = "New", char* l_name = "Employee",  8                   char sex = 'M', int age = 18, float _hourly_rate = 0);  9          virtual ~HourlyEmployee(); 10          float pay(); 11          void setHoursWorked(float hours); 12          float getHoursWorked(); 13          void setHourlyRate(float rate); 14          float getHourlyRate(); 15          int getHourlyEmployeeCount(); 16      private: 17        static int hourly_employee_count; 18        float hourly_rate; 19        float hours_worked; 20  }; 21  #endif
end example

Listing 13.25: salariedemployee.h

start example
  1  #ifndef SALARIED_EMPLOYEE_H  2  #define SALARIED_EMPLOYEE_H  3  #include "employee.h"  4  5  class SalariedEmployee : public Employee{  6     public:  7         SalariedEmployee(char* f_name = "New", char* m_name = "Salaried",  8                           char* l_name = "Employee", char sex = 'M', int age = 18,  9                           float _salary = 0); 10         virtual ~SalariedEmployee(); 11         float pay(); 12         float getSalary(); 13         void setSalary(float _salary); 14         int getSalariedEmployeeCount(); 15     private: 16         static int salaried_employee_count; 17         float salary; 18  }; 19  #endif
end example

Notice how each of these classes have only to inherit from Employee. Since an Employee is a Person and is a Payable, any class than inherits from Employee will be an Employee, a Person, and a Payable, with access to all the functionality the inheritance relationship offers. Also notice that both HourlyEmployee and SalariedEmployee declare the pay() function. This function will override the pure virtual pay() function in Employee, which is the same pure virtual pay() function declared in Payable.

The implementation code for the HourlyEmployee and SalariedEmployee classes is given in examples 13.26 and 13.27.

Listing 13.26: hourlyemployee.cpp

start example
 1  #include "employee.h"  2  #include "hourlyemployee.h"  3  4  5  int HourlyEmployee::hourly_employee_count = 0;  6  7  HourlyEmployee::HourlyEmployee(char* f_name, char* m_name, char* l_name,  8                   char sex, int age, float _hourly_rate):  9                   Employee(f_name, m_name, l_name, sex, age), 10  hourly_rate(_hourly_rate), 11                   hours_worked(0){ 12                   hourly_employee_count++; 13  } 14 15  HourlyEmployee::~HourlyEmployee(){hourly_employee_count--;} 16 17  float HourlyEmployee::pay(){return (hourly_rate * hours_worked);} 18 19  void HourlyEmployee::setHoursWorked(float hours){ 20       hours_worked = hours; 21  } 22 23  float HourlyEmployee::getHoursWorked(){return hours_worked;} 24 25  void HourlyEmployee::setHourlyRate(float rate){ 26       hourly_rate = rate;} 27 28  float HourlyEmployee::getHourlyRate(){return hourly_rate;} 29 30  int HourlyEmployee::getHourlyEmployeeCount(){return hourly_employee_count;}
end example

Listing 13.27: salariedemployee.cpp

start example
  1  #include "employee.h"  2  #include "salariedemployee.h"  3  4  int SalariedEmployee::salaried_employee_count = 0;  5  6  SalariedEmployee::SalariedEmployee(char* f_name, char* m_name, char* l_name,  7                      char sex, int age, float _salary):  8                      Employee(f_name, m_name, l_name, sex, age), salary(_salary){  9                      salaried_employee_count++; 10  } 11 12  SalariedEmployee::~SalariedEmployee(){salaried_employee_count--;} 13 14  float SalariedEmployee::pay(){ return (salary/26);} 15 16  float SalariedEmployee::getSalary(){return salary;} 17 18  void SalariedEmployee::setSalary(float _salary){ 19         salary = _salary; 20  } 21 22  int SalariedEmployee::getSalariedEmployeeCount(){   23       return salaried_employee_count;   24  }
end example

Since most of the work of being a Person and an Employee is already done, each derived class need only implement any additional functions they have declared, including the overriding pay() function. Most of the work for each of these classes takes place in their respective constructors which must call the Employee base class constructor in the initializer list using its parameters. Example 13.28 gives a main.cpp file showing the classes of the payroll application in action. Figure 13-15 shows the results of running example 13.28.

Listing 13.28: main.cpp

start example
  1  #include <iostream>  2  using namespace std;  3  #include <iomanip.h>   4  #include "employee.h"  5  #include "hourlyemployee.h"  6  #include "salariedemployee.h"  7  8  int main(){  9       Employee* employees[2]; 10 11       HourlyEmployee Bob("Bob", "J", "Jones"); 12       Bob.setHoursWorked(80); 13       Bob.setHourlyRate(8.00); 14       cout<<Bob.getHoursWorked()<<" "<<Bob.getHourlyRate()<<" "<<Bob.pay()<<endl; 15 16       SalariedEmployee Sue("Sue", "Mae", "Lind", 'F', 23, 67000.00); 17       cout<<Sue.getSalary()<<" "<<Sue.pay()<<endl; 18 19       employees[0] = &Bob; 20       employees[1] = &Sue;   21 22       cout<<endl<<endl<<endl;   23 24       cout<<"#"<<setw(15)<<"First"<<setw(15)<<"Middle"<<setw(15)<<"Last"<<setw(10)<<"Pay"<<endl; 25       cout<<" -----------------------------------------------------------------"<<endl; 26 27 28       for(int i=0; i<2; i++){ 29         cout<<employees[i]->getEmployeeNumber()<<setw(15)<<employees[i]->getFirstName()   30             <<setw(15)<<employees[i]->getMiddleName()<<setw(15)<<employees[i]->getLastName()   31             <<"       $"<<setw(8)<<employees[i]->pay()<<endl; 32 33  } 34  return 0; 35  }
end example

click to expand
Figure 13-15: Results of Running Example 13.28



 < Day Day Up > 



C++ for Artists. The Art, Philosophy, and Science of Object-Oriented Programming
C++ For Artists: The Art, Philosophy, And Science Of Object-Oriented Programming
ISBN: 1932504028
EAN: 2147483647
Year: 2003
Pages: 340
Authors: Rick Miller

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net