- 实验题目
为某公司设计雇员工资发放系统。
每个雇员的基本信息包括:姓名(name),工号(id)。
雇员的收入取决于雇员的类型。该公司共有四类雇员:
周薪雇员(SalariedEmployee):收入=固定周薪。
时薪雇员(HourlyEmployee):若工作40小时以下,收入=小时数*每小时薪水;若工作40小时以上,收入=40*每小时薪水+(小时数-40)*每小时薪水*150%。
佣金雇员(CommissionEmployee):收入=销售量*每个商品的销售佣金
带底薪佣金雇员(BasePlusCommissionEmployee):收入=底薪+销售量*每个商品的销售佣金
要求:建立雇员继承层次,每个类包含计算工资和显示输出的功能,可以计算和显示输出公司雇员(Employee)的每周收入。输出时要显示该类雇员的所有信息。(包括雇员类型、姓名、工号、工资各项明细),写出主函数测试各类。在雇员基本信息中增加雇员的生日(birthDate),并设计日期类(Date)来表示生日。在主函数中创建一个容器用来管理公司各种雇员对象,多态地计算并输出每个雇员的工资。如果雇员的生日在本月,就奖给该雇员100元。同时,在本次工资发放阶段,公司决定奖励带薪佣金雇员,把他们的基本工资提高10%。
设计提示:使用抽象类。
- 解决方案
1.设计日期类(Date):
包含年(year)、月(month)、日(day)三个成员变量。
提供日期比较(比如是否在本月)的方法。
2.设计雇员基类(Employee):
声明为抽象类。
包含姓名(name)、工号(id)、生日(birthDate)三个成员变量。
声明纯虚函数double calculateSalary()来计算工资。
声明虚函数void display()来显示雇员信息。
3.设计各类雇员类:
从Employee类继承。
实现各自的calculateSalary()函数来根据雇员类型计算工资。
实现display()函数来显示雇员的详细信息。
4.设计主函数:
创建一个包含不同雇员类型的容器(比如std::vector<std::unique_ptr<Employee>>)。
遍历容器,使用多态调用calculateSalary()和display()函数来计算和显示工资。
检查雇员生日是否在本月,并相应调整工资。
对于带底薪佣金雇员,增加10%的基本工资。
注:本程序分别添加了一位周薪雇员,一位时薪雇员,一位佣金雇员,一位带底薪佣金雇员,其中有两位生日在5月。
- 程序清单
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
#include <ctime>
// 日期类
class Date {
public:
int year, month, day;
Date(int y = 0, int m = 0, int d = 0) : year(y), month(m), day(d) {}
// 判断日期是否在当前月份
bool isThisMonth(const time_t& now) const {
struct tm* timeinfo = localtime(&now);
return month == timeinfo->tm_mon + 1;
}
};
// 雇员基类(抽象类)
class Employee {
public:
std::string name;
int id;
Date birthDate;
Employee(const std::string& n, int i, int y, int m, int d)
: name(n), id(i), birthDate(y, m, d) {}
virtual double calculateSalary() const = 0; // 纯虚函数
virtual void display() const = 0; // 纯虚函数
virtual ~Employee() {}
};
// 周薪雇员
class SalariedEmployee : public Employee {
double weeklySalary;
public:
SalariedEmployee(const std::string& n, int i, double s, int y, int m, int d)
: Employee(n, i, y, m, d), weeklySalary(s) {}
double calculateSalary() const override { return weeklySalary; }
void display() const override {
std::cout << "SalariedEmployee: " << name << ", ID: " << id
<< ", Salary: $" << calculateSalary() << std::endl;
}
};
// 时薪雇员
class HourlyEmployee :public Employee {
double everyhourSalary;
double hours;
public:
HourlyEmployee(const std::string& n, int i, double e,double h ,int y, int m, int d)
: Employee(n, i, y, m, d), everyhourSalary(e),hours(h) {}
double calculateSalary() const override {
if (hours <= 40)
return hours * everyhourSalary;
else
return 40 * everyhourSalary + (hours - 40) * everyhourSalary * 1.5;
}
void display() const override {
std::cout << "HourlyEmployee: " << name << ", ID: " << id
<< ", Salary: $" << calculateSalary() << std::endl;
}
};
// 佣金雇员
class CommissionEmployee :public Employee {
int salesvolume;
double everycommission;
public:
CommissionEmployee(const std::string& n, int i, int s, double e, int y, int m, int d)
: Employee(n, i, y, m, d), salesvolume(s), everycommission(e){}
double calculateSalary() const override {
return salesvolume * everycommission;
}
void display() const override {
std::cout << "CommissionEmployee: " << name << ", ID: " << id
<< ", Salary: $" << calculateSalary() << std::endl;
}
};
// 带底薪佣金雇员
class BasePlusCommissionEmployee : public Employee {
double baseSalary;
double commissionRate;
double sales;
public:
BasePlusCommissionEmployee(const std::string& n, int i, double b, double c, double s, int y, int m, int d)
: Employee(n, i, y, m, d), baseSalary(b), commissionRate(c), sales(s) {}
double calculateSalary() const override {
return baseSalary *1.1 + sales * commissionRate;
}
void display() const override {
std::cout << "BasePlusCommissionEmployee: " << name << ", ID: " << id
<< ", Salary: $" << calculateSalary()
<< ", Base Salary: $" << baseSalary *1.1
<< ", Commission: $" << sales * commissionRate
<< std::endl;
}
};
// 主函数
int main() {
std::vector<Employee*> employees;
// 假设今天是5月20日
time_t now = time(nullptr);
struct tm* localTime = localtime(&now);
int currentYear = localTime->tm_year + 1900;
int currentMonth = localTime->tm_mon + 1;
//添加一个周薪雇员
SalariedEmployee* employee_S = new SalariedEmployee("马", 7, 5000.0, 2005, 9, 30);
if (employee_S->birthDate.isThisMonth(now)) {
// 假设这里只是简单打印出奖励信息,实际中可能需要更新雇员的工资或其他属性
std::cout << employee_S->name << " birthday bonus: $100" << std::endl;
}
employees.push_back(employee_S);
//添加一个时薪雇员
HourlyEmployee* employee_H = new HourlyEmployee("陶", 6, 100, 6, 2004, 5, 2);
if (employee_H->birthDate.isThisMonth(now)) {
std::cout << employee_H->name << " birthday bonus: $100" << std::endl;
}
employees.push_back(employee_H);
//添加一个佣金雇员
CommissionEmployee* employee_C = new CommissionEmployee("姜", 5, 120, 23.4, 2006, 11, 12);
if (employee_C->birthDate.isThisMonth(now)) {
std::cout << employee_C->name << " birthday bonus: $100" << std::endl;
}
employees.push_back(employee_C);
//添加一个带底薪佣金雇员
BasePlusCommissionEmployee* employee_B = new BasePlusCommissionEmployee("万", 1, 500.0, 0.1, 1000.0, 1980, 5, 20);
if (employee_B->birthDate.isThisMonth(now)) {
std::cout << employee_B->name << " birthday bonus: $100" << std::endl;
}
employees.push_back(employee_B);
// 遍历并计算和显示每个雇员的工资
for (Employee* emp : employees) {
emp->display();
}
return 0;
}
- 体会与总结
(一)知识点理解
1.抽象类(Abstract Class):
抽象类不能被实例化,通常用于定义一个接口,该接口由派生类实现。
抽象类可以包含纯虚函数(只有声明,没有定义的函数),派生类必须实现这些纯虚函数。
2.继承(Inheritance):
继承允许我们定义一个派生类(子类),它继承了一个或多个基类(父类)的特性(数据成员和成员函数)。
通过继承,子类可以重用父类的代码,并实现自己的特定功能。
3.多态(Polymorphism):
多态允许我们使用父类类型的指针或引用来调用子类对象的方法。
在运行时,根据指针或引用所指向的实际对象类型来确定调用哪个方法。
(二)运行情况分析
在实现雇员工资发放系统时,我们首先需要定义Employee基类,它是一个抽象类,包含了所有雇员的公共属性(如姓名、工号、生日)和纯虚函数(如calculateSalary和display)。然后,我们为每种类型的雇员定义了一个派生类,实现了自己的calculateSalary和display函数。
在主函数中,我们创建了一个std::vector<std::unique_ptr<Employee>>容器来存储不同类型的雇员对象。由于使用了智能指针,我们不需要担心内存泄漏问题。然后,我们遍历容器,使用多态来调用每个雇员的calculateSalary和display函数,计算和显示每个雇员的工资。
对于生日奖励和底薪佣金雇员的奖励,我们可以在调用calculateSalary函数时进行检查和处理。
(三)调试程序获得的经验与体会
在调试程序时,我遇到了几个常见的问题:
1.内存泄漏:由于C++中手动管理内存,很容易忘记释放分配的内存,导致内存泄漏。通过使用智能指针(如std::unique_ptr),我们可以避免这个问题。
2.类型错误:在使用多态时,如果父类和子类的函数签名不一致,或者子类没有实现父类的纯虚函数,编译器会报错。因此,我们需要仔细检查类层次结构中的函数签名。
3.逻辑错误:在计算工资和显示信息时,可能会出现逻辑错误。例如,忘记考虑生日奖励或底薪佣金雇员的奖励。通过编写详细的测试用例并仔细测试每个功能,我们可以发现和修复这些错误。
4.可读性:为了提高代码的可读性,我们应该遵循良好的编程规范,如使用有意义的变量名、添加注释、保持代码结构清晰等。这有助于我们和其他开发人员更好地理解代码。