引言
本博文通过包含了一个公司支付系统中各种雇员情况的一个继承层次来讨论基类和派生类之间的关系.佣金雇员(表示为一个基类对象)的薪水完全是销售提成,带底薪佣雇员(表示为一个派生类的对象)的薪水由底薪和销售提成组成.以及创建一个增强的雇员类层次结构,以解决下面的问题:
- 假设某家公司按周支付雇员工资,雇员一共有有4类:
- 定薪雇员:不管每周工作多长时间都领取固定的周薪
- 钟点雇员:按工作的小时数领取工资,并且可以领取超过40个小时之外的加班费
- 佣金雇员:工资完全是销售业绩提成
- 带薪佣雇员:工资是基本工资和销售提成组成
- 在这次工资发放阶级,公司决定奖励带佣金雇员,把他们的基本工资提高10%.公司想实现一个C++程序多态地执行工资的计算.
我们使用抽象类Employee表示通常概念的雇员.直接从Employee类派生的是类SalariedEmployee,CommissionEmployee 和HourlyEmployee.而BasePlusCommissionEmployee类又是从CommissionEmployee类直接派生的,代表最后一种雇员类型.如图1所中的UML图显示多态的雇员工资应用程序中类的继承层次结构.
![]()
图1:雇员类型层次结构的UML图
抽象类Employee声明了类层次结构的"接口",即程序可以对所有的Employee类对象调用的一组成员函数集合.每个雇员,不论他的工资计算方式如何,都有名,姓及社会安全号码,因此在抽象基类Employee中含有private数据成员firstName ,lastName和 socialSecurityNumber.接下来的内容将实现上述的Employee类层次结构.在最后构建一个测试程序,它创建所有这些类的对象并多态地处理对象.
创建抽象基类: Employee类
图2给出了图表类继承层次中的5个类,顶部显示的是earnings和print函数名.对于每个类,这张图表显示了每个函数期望的实现.注意在Employee类中earnings函数被指定"=0",表示它是一个纯virtual函数.每个派生类都重写earnings函数,提供合适的实现.
![]()
图2:Employee类层次结构的多态性接口
让我们考虑Employee类头文件(如下程序所示).public成员函数包括:一个构造函数,该构造函数以名,姓及社会安全号码为参数;设置函数名,姓及社会安全号码;获取函数,返回了名,姓及社会安全号码;以及纯virtual 函数earnings和virtual函数print;
Employee类头文件
-
- #ifndef EMPLOYEE_H
- #define EMPLOYEE_H
-
- #include <string> // C++ standard string class
- using std::string;
-
- class Employee
- {
- public:
- Employee( const string &, const string &, const string & );
-
- void setFirstName( const string & );
- string getFirstName() const;
-
- void setLastName( const string & );
- string getLastName() const;
-
- void setSocialSecurityNumber( const string & );
- string getSocialSecurityNumber() const;
-
-
- virtual double earnings() const = 0;
- virtual void print() const;
- private:
- string firstName;
- string lastName;
- string socialSecurityNumber;
- };
-
- #endif // EMPLOYEE_H
而 Employee类的实现文件中,没有为纯virtual 函数earnings提供任何实现.请注意: Employee类的构造函数并没有确认社会号码的有效性.通常应该提供这类有效性确认.
Employee类的实现文件
-
-
- #include <iostream>
- using std::cout;
-
- #include "Employee.h" // Employee class definition
-
-
- Employee::Employee( const string &first, const string &last,
- const string &ssn )
- : firstName( first ), lastName( last ), socialSecurityNumber( ssn )
- {
-
- }
-
-
- void Employee::setFirstName( const string &first )
- {
- firstName = first;
- }
-
-
- string Employee::getFirstName() const
- {
- return firstName;
- }
-
-
- void Employee::setLastName( const string &last )
- {
- lastName = last;
- }
-
-
- string Employee::getLastName() const
- {
- return lastName;
- }
-
-
- void Employee::setSocialSecurityNumber( const string &ssn )
- {
- socialSecurityNumber = ssn;
- }
-
-
- string Employee::getSocialSecurityNumber() const
- {
- return socialSecurityNumber;
- }
-
-
- void Employee::print() const
- {
- cout << getFirstName() << ' ' << getLastName()
- << "\nsocial security number: " << getSocialSecurityNumber();
- }
注意:virtual函数print提供的实现会在每个派生类中被重写.可是,这些print函数都将使用这个抽象类中print函数的版本,输出Employee声明了类层次结构中所有类共有的信息.
创建具体的派生类: SalariedEmployee类
SalariedEmployee类是从Employee类派生而来的,其public成员函数包括:一个以名, 姓,社会安全号码和周薪为参数的构造函数;给数据成员weeklySalary赋一个非负的设置函数;返回weeklySalary值的获取函数;计算一个SalariedEmployee雇员收入的virtual函数earnings;打印雇员信息的virtual函数print,它输出的内容依次是雇员类型(即:"salaried employee").以及由基类Employee的print函数和SalariedEmployee类的 getWeeklySalary函数产生的雇员的特定信息.
SalariedEmployee类头文件
-
- #ifndef SALARIED_H
- #define SALARIED_H
-
- #include "Employee.h" // Employee class definition
-
- class SalariedEmployee : public Employee
- {
- public:
- SalariedEmployee( const string &, const string &,
- const string &, double = 0.0 );
-
- void setWeeklySalary( double );
- double getWeeklySalary() const;
-
-
- virtual double earnings() const;
- virtual void print() const;
- private:
- double weeklySalary;
- };
-
- #endif // SALARIED_H
SalariedEmployee类的成员函数的实现.类的构造函数把名,姓和社会安全号码传递给基类Employee的构造函数,从而对从基类继承但在派行类中不可访问的private数据成员进行了初始化.SalariedEmployee类的print函数重写了基类Employee的print函数.如果SalariedEmployee类不重写print函数,那么SalariedEmployee类将继承基类Employee的print函数.
SalariedEmployee类实现文件
-
- #include <iostream>
- using std::cout;
-
- #include "SalariedEmployee.h" // SalariedEmployee class definition
-
-
- SalariedEmployee::SalariedEmployee( const string &first,
- const string &last, const string &ssn, double salary )
- : Employee( first, last, ssn )
- {
- setWeeklySalary( salary );
- }
-
-
- void SalariedEmployee::setWeeklySalary( double salary )
- {
- weeklySalary = ( salary < 0.0 ) ? 0.0 : salary;
- }
-
-
- double SalariedEmployee::getWeeklySalary() const
- {
- return weeklySalary;
- }
-
-
-
- double SalariedEmployee::earnings() const
- {
- return getWeeklySalary();
- }
-
-
- void SalariedEmployee::print() const
- {
- cout << "salaried employee: ";
- Employee::print();
- cout << "\nweekly salary: " << getWeeklySalary();
- }
创建具体的派生类: HourlyEmployee类
HourlyEmployee类头文件
-
-
- #ifndef HOURLY_H
- #define HOURLY_H
-
- #include "Employee.h" // Employee class definition
-
- class HourlyEmployee : public Employee
- {
- public:
- HourlyEmployee( const string &, const string &,
- const string &, double = 0.0, double = 0.0 );
-
- void setWage( double );
- double getWage() const;
-
- void setHours( double );
- double getHours() const;
-
-
- virtual double earnings() const;
- virtual void print() const;
- private:
- double wage;
- double hours;
- };
-
- #endif // HOURLY_H
HourlyEmployee类实现文件
// HourlyEmployee.cpp: HourlyEmployee class member-function definitions.
#include <iostream>
using std::cout;
#include "HourlyEmployee.h" // HourlyEmployee class definition
// constructor
HourlyEmployee::HourlyEmployee(const string &first, const string &last,
const string &ssn, double hourlyWage, double hoursWorked)
: Employee(first, last, ssn)
{
setWage(hourlyWage); // validate hourly wage
setHours(hoursWorked); // validate hours worked
} // end HourlyEmployee constructor
// set wage
void HourlyEmployee::setWage(double hourlyWage)
{
wage = hourlyWage < 0.0 ? 0.0 : hourlyWage;
} // end function setWage
// return wage
double HourlyEmployee::getWage() const
{
return wage;
} // end function getWage
// set hours worked
void HourlyEmployee::setHours(double hoursWorked)
{
hours = hoursWorked < 0.0 ? 0.0 : hoursWorked;
}
double HourlyEmployee::getHours() const
{
return hours;
}
double HourlyEmployee::earnings() const
{
return getWage() * getHours();
}
void HourlyEmployee::print() const
{
cout << "Hourly employee: ";
Employee::print(); // code reuse
cout << "\nwage: " << getWage()
<< "; hours: " << getHours();
}
创建具体的派生类: CommissionEmployee类
CommissionEmployee类头文件
-
- #ifndef COMMISSION_H
- #define COMMISSION_H
-
- #include "Employee.h" // Employee class definition
-
- class CommissionEmployee : public Employee
- {
- public:
- CommissionEmployee( const string &, const string &,
- const string &, double = 0.0, double = 0.0 );
-
- void setCommissionRate( double );
- double getCommissionRate() const;
-
- void setGrossSales( double );
- double getGrossSales() const;
-
-
- virtual double earnings() const;
- virtual void print() const;
- private:
- double grossSales;
- double commissionRate;
- };
-
- #endif // COMMISSION_H
CommissionEmployee类实现文件
-
- #include <iostream>
- using std::cout;
-
- #include "CommissionEmployee.h" // CommissionEmployee class definition
-
-
- CommissionEmployee::CommissionEmployee( const string &first,
- const string &last, const string &ssn, double sales, double rate )
- : Employee( first, last, ssn )
- {
- setGrossSales( sales );
- setCommissionRate( rate );
- }
-
-
- void CommissionEmployee::setCommissionRate( double rate )
- {
- commissionRate = ( rate > 0.0 && rate < 1.0 ) ? rate : 0.0;
- }
-
-
- double CommissionEmployee::getCommissionRate() const
- {
- return commissionRate;
- }
-
-
- void CommissionEmployee::setGrossSales( double sales )
- {
- grossSales = ( sales < 0.0 ) ? 0.0 : sales;
- }
-
-
- double CommissionEmployee::getGrossSales() const
- {
- return grossSales;
- }
-
-
-
- double CommissionEmployee::earnings() const
- {
- return getCommissionRate() * getGrossSales();
- }
-
-
- void CommissionEmployee::print() const
- {
- cout << "commission employee: ";
- Employee::print();
- cout << "\ngross sales: " << getGrossSales()
- << "; commission rate: " << getCommissionRate();
- }
创建具体的派生类: BasePlusCommissionEmployee类
BasePlusCommissionEmployee类头文件
-
-
- #ifndef BASEPLUS_H
- #define BASEPLUS_H
-
- #include "CommissionEmployee.h" // CommissionEmployee class definition
-
- class BasePlusCommissionEmployee : public CommissionEmployee
- {
- public:
- BasePlusCommissionEmployee( const string &, const string &,
- const string &, double = 0.0, double = 0.0, double = 0.0 );
-
- void setBaseSalary( double );
- double getBaseSalary() const;
-
-
- virtual double earnings() const;
- virtual void print() const;
- private:
- double baseSalary;
- };
-
- #endif // BASEPLUS_H
BasePlusCommissionEmployee类实现文件
-
- #include <iostream>
- using std::cout;
-
-
- #include "BasePlusCommissionEmployee.h"
-
-
- BasePlusCommissionEmployee::BasePlusCommissionEmployee(
- const string &first, const string &last, const string &ssn,
- double sales, double rate, double salary )
- : CommissionEmployee( first, last, ssn, sales, rate )
- {
- setBaseSalary( salary );
- }
-
-
- void BasePlusCommissionEmployee::setBaseSalary( double salary )
- {
- baseSalary = ( salary < 0.0 ) ? 0.0 : salary;
- }
-
-
- double BasePlusCommissionEmployee::getBaseSalary() const
- {
- return baseSalary;
- }
-
-
-
- double BasePlusCommissionEmployee::earnings() const
- {
- return getBaseSalary() + CommissionEmployee::earnings();
- }
-
-
- void BasePlusCommissionEmployee::print() const
- {
- cout << "base-salaried ";
- CommissionEmployee::print();
- cout << "; base salary: " << getBaseSalary();
- }
演示多态性的执行过程
为了测试Employee类层次结构,如下所示程序中的程序为4个具体类 SalariedEmployee, HourlyEmployee, CommissionEmployee和BasePlusCommissionEmployee的每一个都创建了一个对象.程序首先使用静态绑定方式对这些对象进行了操作,然后使用Employee指针的vector多态地对这些对象进行操作.
Employee类层次结构的驱动程序
-
-
-
- #include <iostream>
- using std::cout;
- using std::endl;
- using std::fixed;
-
- #include <iomanip>
- using std::setprecision;
-
- #include <vector>
- using std::vector;
-
- #include <typeinfo>
-
-
- #include "Employee.h"
- #include "SalariedEmployee.h"
- #include "HourlyEmployee.h"
- #include "CommissionEmployee.h"
- #include "BasePlusCommissionEmployee.h"
-
- int main()
- {
-
- cout << fixed << setprecision( 2 );
-
-
- vector < Employee * > employees( 4 );
-
-
- employees[ 0 ] = new SalariedEmployee(
- "John", "Smith", "111-11-1111", 800 );
- employees[ 1 ] = new HourlyEmployee(
- "Karen", "Price", "222-22-2222", 16.75, 40 );
- employees[ 2 ] = new CommissionEmployee(
- "Sue", "Jones", "333-33-3333", 10000, .06 );
- employees[ 3 ] = new BasePlusCommissionEmployee(
- "Bob", "Lewis", "444-44-4444", 5000, .04, 300 );
-
-
- for ( size_t i = 0; i < employees.size(); i++ )
- {
- employees[ i ]->print();
- cout << endl;
-
-
- BasePlusCommissionEmployee *derivedPtr =
- dynamic_cast < BasePlusCommissionEmployee * >
- ( employees[ i ] );
-
-
-
- if ( derivedPtr != 0 )
- {
- double oldBaseSalary = derivedPtr->getBaseSalary();
- cout << "old base salary: $" << oldBaseSalary << endl;
- derivedPtr->setBaseSalary( 1.10 * oldBaseSalary );
- cout << "new base salary with 10% increase is: $"
- << derivedPtr->getBaseSalary() << endl;
- }
-
- cout << "earned $" << employees[ i ]->earnings() << "\n\n";
- }
-
-
- for ( size_t j = 0; j < employees.size(); j++ )
- {
-
- cout << "deleting object of "
- << typeid( *employees[ j ] ).name() << endl;
-
- delete employees[ j ];
- }
-
- return 0;
- }
输出结果:
![]()
![]()