引言
本博文通过包含了一个公司支付系统中各种雇员情况的一个继承层次来讨论基类和派生类之间的关系.佣金雇员(表示为一个基类对象)的薪水完全是销售提成,带底薪佣雇员(表示为一个派生类的对象)的薪水由底薪和销售提成组成.以及创建一个增强的雇员类层次结构,以解决下面的问题:
- 假设某家公司按周支付雇员工资,雇员一共有有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类头文件
// Employee.h: Employee abstract base class.
#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 & ); // set first name
string getFirstName() const; // return first name
void setLastName( const string & ); // set last name
string getLastName() const; // return last name
void setSocialSecurityNumber( const string & ); // set SSN
string getSocialSecurityNumber() const; // return SSN
// pure virtual function makes Employee abstract base class
virtual double earnings() const = 0; // pure virtual
virtual void print() const; // virtual
private:
string firstName;
string lastName;
string socialSecurityNumber;
}; // end class Employee
#endif // EMPLOYEE_H
而 Employee类的实现文件中,没有为纯virtual 函数earnings提供任何实现.请注意: Employee类的构造函数并没有确认社会号码的有效性.通常应该提供这类有效性确认.
Employee类的实现文件
// Employee.cpp: Abstract-base-class Employee member-function definitions.
// Note: No definitions are given for pure virtual functions.
#include <iostream>
using std::cout;
#include "Employee.h" // Employee class definition
// constructor
Employee::Employee( const string &first, const string &last,
const string &ssn )
: firstName( first ), lastName( last ), socialSecurityNumber( ssn )
{
// empty body
} // end Employee constructor
// set first name
void Employee::setFirstName( const string &first )
{
firstName = first;
} // end function setFirstName
// return first name
string Employee::getFirstName() const
{
return firstName;
} // end function getFirstName
// set last name
void Employee::setLastName( const string &last )
{
lastName = last;
} // end function setLastName
// return last name
string Employee::getLastName() const
{
return lastName;
} // end function getLastName
// set social security number
void Employee::setSocialSecurityNumber( const string &ssn )
{
socialSecurityNumber = ssn; // should validate
} // end function setSocialSecurityNumber
// return social security number
string Employee::getSocialSecurityNumber() const
{
return socialSecurityNumber;
} // end function getSocialSecurityNumber
// print Employee's information
void Employee::print() const
{
cout << getFirstName() << ' ' << getLastName()
<< "\nsocial security number: " << getSocialSecurityNumber();
} // end function print
注意:virtual函数print提供的实现会在每个派生类中被重写.可是,这些print函数都将使用这个抽象类中print函数的版本,输出Employee声明了类层次结构中所有类共有的信息.
创建具体的派生类: SalariedEmployee类
SalariedEmployee类是从Employee类派生而来的,其public成员函数包括:一个以名, 姓,社会安全号码和周薪为参数的构造函数;给数据成员weeklySalary赋一个非负的设置函数;返回weeklySalary值的获取函数;计算一个SalariedEmployee雇员收入的virtual函数earnings;打印雇员信息的virtual函数print,它输出的内容依次是雇员类型(即:"salaried employee").以及由基类Employee的print函数和SalariedEmployee类的 getWeeklySalary函数产生的雇员的特定信息.
SalariedEmployee类头文件
// SalariedEmployee.h: SalariedEmployee class derived from Employee.
#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 ); // set weekly salary
double getWeeklySalary() const; // return weekly salary
// keyword virtual signals intent to override
virtual double earnings() const; // calculate earnings
virtual void print() const; // print SalariedEmployee object
private:
double weeklySalary; // salary per week
}; // end class SalariedEmployee
#endif // SALARIED_H
SalariedEmployee类的成员函数的实现.类的构造函数把名,姓和社会安全号码传递给基类Employee的构造函数,从而对从基类继承但在派行类中不可访问的private数据成员进行了初始化.SalariedEmployee类的print函数重写了基类Employee的print函数.如果SalariedEmployee类不重写print函数,那么SalariedEmployee类将继承基类Employee的print函数.
SalariedEmployee类实现文件
// SalariedEmployee.cpp :SalariedEmployee class member-function definitions.
#include <iostream>
using std::cout;
#include "SalariedEmployee.h" // SalariedEmployee class definition
// constructor
SalariedEmployee::SalariedEmployee( const string &first,
const string &last, const string &ssn, double salary )
: Employee( first, last, ssn )
{
setWeeklySalary( salary );
} // end SalariedEmployee constructor
// set salary
void SalariedEmployee::setWeeklySalary( double salary )
{
weeklySalary = ( salary < 0.0 ) ? 0.0 : salary;
} // end function setWeeklySalary
// return salary
double SalariedEmployee::getWeeklySalary() const
{
return weeklySalary;
} // end function getWeeklySalary
// calculate earnings;
// override pure virtual function earnings in Employee
double SalariedEmployee::earnings() const
{
return getWeeklySalary();
} // end function earnings
// print SalariedEmployee's information
void SalariedEmployee::print() const
{
cout << "salaried employee: ";
Employee::print(); // code reuse
cout << "\nweekly salary: " << getWeeklySalary();
} // end function print
创建具体的派生类: HourlyEmployee类
HourlyEmployee类头文件
// HourlyEmployee.h
// HourlyEmployee class definition.
#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 ); // set hourly wage
double getWage() const; // return hourly wage
void setHours( double ); // set hours worked
double getHours() const; // return hours worked
// keyword virtual signals intent to override
virtual double earnings() const; // calculate earnings
virtual void print() const; // print HourlyEmployee object
private:
double wage; // wage per hour
double hours; // hours worked for week
}; // end class HourlyEmployee
#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
创建具体的派生类: CommissionEmployee类
CommissionEmployee类头文件
// CommissionEmployee.h: CommissionEmployee class derived from Employee.
#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 ); // set commission rate
double getCommissionRate() const; // return commission rate
void setGrossSales( double ); // set gross sales amount
double getGrossSales() const; // return gross sales amount
// keyword virtual signals intent to override
virtual double earnings() const; // calculate earnings
virtual void print() const; // print CommissionEmployee object
private:
double grossSales; // gross weekly sales
double commissionRate; // commission percentage
}; // end class CommissionEmployee
#endif // COMMISSION_H
CommissionEmployee类实现文件
// CommissionEmployee.cpp: CommissionEmployee class member-function definitions.
#include <iostream>
using std::cout;
#include "CommissionEmployee.h" // CommissionEmployee class definition
// constructor
CommissionEmployee::CommissionEmployee( const string &first,
const string &last, const string &ssn, double sales, double rate )
: Employee( first, last, ssn )
{
setGrossSales( sales );
setCommissionRate( rate );
} // end CommissionEmployee constructor
// set commission rate
void CommissionEmployee::setCommissionRate( double rate )
{
commissionRate = ( rate > 0.0 && rate < 1.0 ) ? rate : 0.0;
} // end function setCommissionRate
// return commission rate
double CommissionEmployee::getCommissionRate() const
{
return commissionRate;
} // end function getCommissionRate
// set gross sales amount
void CommissionEmployee::setGrossSales( double sales )
{
grossSales = ( sales < 0.0 ) ? 0.0 : sales;
} // end function setGrossSales
// return gross sales amount
double CommissionEmployee::getGrossSales() const
{
return grossSales;
} // end function getGrossSales
// calculate earnings;
// override pure virtual function earnings in Employee
double CommissionEmployee::earnings() const
{
return getCommissionRate() * getGrossSales();
} // end function earnings
// print CommissionEmployee's information
void CommissionEmployee::print() const
{
cout << "commission employee: ";
Employee::print(); // code reuse
cout << "\ngross sales: " << getGrossSales()
<< "; commission rate: " << getCommissionRate();
} // end function print
创建具体的派生类: BasePlusCommissionEmployee类
BasePlusCommissionEmployee类头文件
// BasePlusCommissionEmployee.h
// BasePlusCommissionEmployee class derived from Employee.
#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 ); // set base salary
double getBaseSalary() const; // return base salary
// keyword virtual signals intent to override
virtual double earnings() const; // calculate earnings
virtual void print() const; // print BasePlusCommissionEmployee object
private:
double baseSalary; // base salary per week
}; // end class BasePlusCommissionEmployee
#endif // BASEPLUS_H
BasePlusCommissionEmployee类实现文件
// BasePlusCommissionEmployee.cpp: BasePlusCommissionEmployee member-function definitions.
#include <iostream>
using std::cout;
// BasePlusCommissionEmployee class definition
#include "BasePlusCommissionEmployee.h"
// constructor
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 ); // validate and store base salary
} // end BasePlusCommissionEmployee constructor
// set base salary
void BasePlusCommissionEmployee::setBaseSalary( double salary )
{
baseSalary = ( salary < 0.0 ) ? 0.0 : salary;
} // end function setBaseSalary
// return base salary
double BasePlusCommissionEmployee::getBaseSalary() const
{
return baseSalary;
} // end function getBaseSalary
// calculate earnings;
// override pure virtual function earnings in Employee
double BasePlusCommissionEmployee::earnings() const
{
return getBaseSalary() + CommissionEmployee::earnings();
} // end function earnings
// print BasePlusCommissionEmployee's information
void BasePlusCommissionEmployee::print() const
{
cout << "base-salaried ";
CommissionEmployee::print(); // code reuse
cout << "; base salary: " << getBaseSalary();
} // end function print
演示多态性的执行过程
为了测试Employee类层次结构,如下所示程序中的程序为4个具体类 SalariedEmployee, HourlyEmployee, CommissionEmployee和BasePlusCommissionEmployee的每一个都创建了一个对象.程序首先使用静态绑定方式对这些对象进行了操作,然后使用Employee指针的vector多态地对这些对象进行操作.
Employee类层次结构的驱动程序
// Demonstrating downcasting and run-time type information.
// NOTE: For this example to run in Visual C++ .NET,
// you need to enable RTTI (Run-Time Type Info) for the project.
#include <iostream>
using std::cout;
using std::endl;
using std::fixed;
#include <iomanip>
using std::setprecision;
#include <vector>
using std::vector;
#include <typeinfo>
// include definitions of classes in Employee hierarchy
#include "Employee.h"
#include "SalariedEmployee.h"
#include "HourlyEmployee.h"
#include "CommissionEmployee.h"
#include "BasePlusCommissionEmployee.h"
int main()
{
// set floating-point output formatting
cout << fixed << setprecision( 2 );
// create vector of four base-class pointers
vector < Employee * > employees( 4 );
// initialize vector with various kinds of Employees
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 );
// polymorphically process each element in vector employees
for ( size_t i = 0; i < employees.size(); i++ )
{
employees[ i ]->print(); // output employee information
cout << endl;
// downcast pointer
BasePlusCommissionEmployee *derivedPtr =
dynamic_cast < BasePlusCommissionEmployee * >
( employees[ i ] );
// determine whether element points to base-salaried
// commission employee
if ( derivedPtr != 0 ) // 0 if not a BasePlusCommissionEmployee
{
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;
} // end if
cout << "earned $" << employees[ i ]->earnings() << "\n\n";
} // end for
// release objects pointed to by vector抯 elements
for ( size_t j = 0; j < employees.size(); j++ )
{
// output class name
cout << "deleting object of "
<< typeid( *employees[ j ] ).name() << endl;
delete employees[ j ];
} // end for
return 0;
} // end main
输出结果:
关于Program Language更多讨论与交流,敬请关注本博客和新浪微博songzi_tea.