C++经典题目雇员问题
本节,我们以一个小型公司的人员信息管理为例,说明类的派生过程及虚函数和虚基类的应用。1. 问题的提出 某小型公司,主要有四类人员:经理、兼职技术人员、销售经理和兼职推销员。现在,需要存储这些人员的姓名、编号、级别、当月薪水.计算月薪总额并显示全部信息。 人员编号基数为1000,每输入一个人员信息编号顺序加1。 程序要有对所有人员提升级别的功能。本例中为简单起见,所有人员的初始级别均为1级。然后进行升级,经理升为4级,兼职技术人员和销售经理升为3级,推销员仍为1级。 月薪计算办法是: 经理拿固定月薪8000元;兼职技术人员按每小时100元领取月薪; 兼职推销员的月薪按该推销员当月销售额的4%提成;销售经理既拿固定月薪也领取销售提成,固定月薪为5000元,销售提成为所管辖部门当月销售总额的5%。2. 类设计 根据上述需求,设计一个基类employee, 然后派生出technician(兼职技术人员)类、manager(经理)类和salesman(兼职推销员)类。由于销售经理既是经理又是销售人员,兼具两类人员的特点, 因此同时继承manager和salesman两个类。 在基类中,除了定义构造函数和析构函数以外,还应统一定义对各类人员信息应有的操作,这样可以规范类族中各派生类的基本行为。但是各类人员的月薪计算方法不同,不能在基类employee中统一确定计算方法。各类人员信息的显示内容也不同,同样不能在基类employee中统一确定显示方法。在基类employee中将pay()和displayStatus()设计为纯虚函数。这样,在主函数中变可以依据赋值兼容规则用基类employee类型的指针数组来处理不同派生类的对象,这是因为当用基类类型的指针调用虚函数时,系统会执行指针所指的对象的成员函数。 由于本例的问题比较简单,因此对于类图中各类属性的详细说明请参看源程序注释。由于salesmanager类的两个基类又有公共基类employee,为了避免二义性,这里将employee设计为虚基类。 //employee.h class employee { protected: char *name; //姓名 int individualEmpNo; //个人编号 int grade; //级别 float accumPay; //月薪总额 static int employeeNo; //本公司职员编号目前最大值 public: employee(); //构造函数 ~employee(); //析构函数 virtual voidpay()=0; //计算月薪函数(纯虚函数) virtual voidpromote(int increment二0); //升级函数(虚函数) virtual void displayStatus()=0; //显示人员信息(纯虚函数) }; class technician:public employee //兼职技术人员类 { private: float hourlyRate; //每小时酬金 int workHours; //当月工作时数 public: technician(); //构造函数 void promote(int); //升级函数 void pay(); //计算月薪函数 void displayStatus(); //显示人员信息 }; class salesman:virtual public employee //兼职推销员类 { protected: float CommRate; //按销售额提取酬金的百分比 float sales: //当月销售额 public: salesman(); //构造函数 void promote(int); //升级函数 void pay(); //计算月薪函数 void displayStatus(); //显示人员信息 }; class manager:virtual public employee //经理类 { protected: float monthlyPay; //固定月薪数 public: manager(); //构造函数 void promote(int); //升级函数 void pay(); //计算月薪函数 void displayStatus(); //显示。人员信息 }; class salesmanager:public manager,public salesman //销售经理类 { public: salesmanager(); //构造函数 void promote(int); //升级函数 ‘ void pay(); //计算月薪函数 void displayStatus(); //显示人员信息 }; //empfunc.cpp #include #include #include”employee.h” int employee::employeeNo=1000; //员工编号基数为1000 employee::employee() { char namestr[50]; //输人雇员姓名时首先临时存放在namestr中 cout cin>>namestr; name=newchar[strlen(namestr)+1]; //动态申请用于存放姓名的内存空间 strcpy(name,namestr); //将临时存放的姓名复制到name individualEmpNo=emptoyeeNo++; //新输入的员工,其编号为目前最大编号加l grade=1; //级别初值为l accumPay=0.0; //月薪总额初值为0 } employee::~employee() { delete name; //在析构函数中删除为存放姓名动态分配的内存空间 } voidemployee::promote(int increment) { grade+=increment; //升级,提升的级数由increment指定 } techniCian::technician() { hourlyRate=100; //每小时酬金100元 } voidtechniCian::promote(int) { employee::promote(2); //调用基类的升级函数,升2级 } void technician::pay() { cout cin>>workHours; accumPay=hourlyRate*workHours;//计算月薪,按小时计酬 cout } void technician::displayStatus() { cout } salesman::salesman() { CommRate=0.04; //销售提成比例4% } void salesman::promote(int) { employee::promote(0); //调用基类的升级函数,升0级 } void salseman::pay() { cout cin>>sales; accumPay=sales*CommRate; //月薪二销售提成 cout } void salesman::displaystatus() { cout } manager::manager() { monthlyPay=8000; //固定月薪8000元 } void manager::promote(int) { employee::promote(3); //调用基类的升级函数,升3级 } void manager::pay() { accumPay=monthlyPay; //月薪总额即固定月薪数 cout commRate=0.005; } void salesmanager::promote(int) { employee::promote(2); //调用基类的升级函数,升2级 } void salesmanager::pay() { cout 本章小结 结构化程序设计强调程序的功能,它以函数(一个功能单位)为中心,分层逐步展开程序设计。但是功能的大小界定,没有统一的标准,不同程序员的设计,反映了不同的思维、程序组织和风格,这给理解程序带来了阴影。同时,它不能隐藏数据复杂性,强迫主程序员必须懂业务、懂计算机以及具有深层次的知识背景。 面向对象程序设计强调程序的分层分类概念,它以抽象为基础,轻灵地描述问题解决的大体思想,以此为基础,进行对象的定义与对象的展示,亦即程序设计,即高层次的抽象程序设计。与此相对应,进行“描述问题解决的大体思想”的具体实现,即类的内部实现(成员函数定义)。 类定义是面向对象程序设计中的基础问题,对象定义是面向对象程序设计的一般操作定义类的过程要求了解问题中的一些东西,组织思想和弄清本质。 类是很容易想象的,如果选择了一个错误的类,则描述起来很困难;如果是正确的类,则将很容易理解它,并清楚地描述出其成员函数和数据成员。 面向对象程序设计的关键是如何抽象与分类。在开发大型软件的时候,要用到面向对象的分析设计技术,它不在本书讨论的范围。 Josephus问题我们再次提了出来。它在这里用来说明面向对象程序设计和结构化程序 设计各自的设计方法,以及其本质的区别。 面向对象程序的维护使我们领略维护并不像结构化程序设计那样大面积展开,而是“各司其职”。