引言
本博文通过包含了一个公司支付系统中各种雇员情况的一个继承层次来讨论基类和派生类之间的关系.佣金雇员(表示为一个基类对象)的薪水完全是销售提成,带底薪佣雇员(表示为一个派生类的对象)的薪水由底薪和销售提成组成.以及创建一个增强的雇员类层次结构,以解决下面的问题:
- 假设某家公司按周支付雇员工资,雇员一共有有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.