8、C++项目实战:职工信息管理系统(继承与多态)
说实话,很多初学者学完C++的继承和多态,总觉得是纸上谈兵。我当年也一样,背了一堆虚函数表、抽象类的概念,但真要写个能跑的系统,脑子就一片空白。
这个项目,就是让你把继承和多态真正用起来。咱们要做一个职工信息管理系统,管理不同岗位的员工——经理、技术人员、销售员。每个岗位的工资计算方式不一样,但系统得统一处理。你想想看,这不就是多态的经典场景吗?
项目需求分析
先理清楚我们要做什么。系统需要管理三类员工:
- 经理:固定月薪,比如8000块
- 技术人员:按工作小时计费,每小时200元
- 销售员:底薪加提成,底薪4000,提成按销售额的5%算
系统功能包括:添加员工、删除员工、修改信息、查询员工、显示所有员工工资。嗯,这里要注意,所有员工都得有编号、姓名、岗位类型这些基本信息。
类结构设计
核心思路是:设计一个抽象基类 Employee,里面放公共属性和一个纯虚函数 calcSalary()。然后三个派生类各自实现自己的工资计算逻辑。
关键设计点:
- 基类用纯虚函数强制子类实现工资计算
- 用虚析构函数确保派生类资源正确释放
- 用
vector<Employee*>存储多态对象
我个人习惯把基类的接口设计得尽量简洁。你看下面这个基类,就三个虚函数:一个算工资,一个显示信息,一个返回岗位类型。够用就行,别整太复杂。
// Employee.h
#pragma once
#include <string>
#include <iostream>
class Employee {
protected:
int id;
std::string name;
std::string position;
public:
Employee(int id, const std::string& name, const std::string& pos)
: id(id), name(name), position(pos) {}
virtual ~Employee() {} // 虚析构,重要!
virtual double calcSalary() const = 0; // 纯虚函数
virtual void showInfo() const {
std::cout << "编号: " << id
<< " 姓名: " << name
<< " 岗位: " << position;
}
int getId() const { return id; }
std::string getPosition() const { return position; }
};
避坑指南:我曾经在项目里忘了给基类写虚析构函数,结果删除派生类对象时只调了基类析构,派生类里动态分配的内存全泄漏了。那会儿排查了一下午,最后发现是少了个 virtual 关键字。所以记住:只要基类有虚函数,析构函数一定要加 virtual。
派生类实现
三个派生类的实现其实很直接。我挑一个技术人员的类给你看看:
// Technician.h
#pragma once
#include "Employee.h"
class Technician : public Employee {
private:
double workHours;
static const double HOURLY_RATE; // 每小时200元
public:
Technician(int id, const std::string& name, double hours)
: Employee(id, name, "技术人员"), workHours(hours) {}
double calcSalary() const override {
return workHours * HOURLY_RATE;
}
void showInfo() const override {
Employee::showInfo();
std::cout << " 工时: " << workHours
<< " 时薪: " << HOURLY_RATE
<< " 工资: " << calcSalary() << std::endl;
}
};
const double Technician::HOURLY_RATE = 200.0;
经理和销售员的实现类似,只是工资计算逻辑不同:
- Manager:直接返回固定月薪
8000.0 - Salesman:返回
baseSalary + salesAmount * 0.05
多态的核心用法
系统管理所有员工时,我们用基类指针的容器来存储:
std::vector<Employee*> employees;
// 添加员工
employees.push_back(new Manager(1001, "张三"));
employees.push_back(new Technician(1002, "李四", 160.0));
employees.push_back(new Salesman(1003, "王五", 50000.0));
// 遍历计算工资——多态就在这里体现
for (const auto& emp : employees) {
emp->showInfo(); // 调用的是实际对象的showInfo
std::cout << "本月工资: " << emp->calcSalary() << "元" << std::endl;
}
// 记得释放内存
for (auto& emp : employees) {
delete emp;
}
employees.clear();
你看,循环里调用 calcSalary() 时,根本不用管它到底是经理还是销售员。C++的虚函数机制会自动找到正确的函数来执行。这就是多态的魅力——写一次循环,处理所有类型。
系统核心逻辑流程图
下面这张图展示了整个系统的类关系和调用流程,我建议你仔细看看:
完整系统功能实现
系统的主控逻辑其实就是一个菜单循环,根据用户选择执行不同操作。我给出核心的几个函数签名:
class EmployeeManager {
private:
std::vector<Employee*> employees;
int nextId;
public:
EmployeeManager() : nextId(1001) {}
~EmployeeManager();
void addEmployee(); // 添加员工
void deleteEmployee(); // 删除员工
void modifyEmployee(); // 修改员工信息
void queryEmployee(); // 查询员工
void showAllSalary(); // 显示所有员工工资
void run(); // 主菜单循环
};
在 addEmployee() 里,根据用户选择的岗位类型,创建不同的派生类对象:
void EmployeeManager::addEmployee() {
std::string name;
int type;
std::cout << "请输入姓名: ";
std::cin >> name;
std::cout << "选择岗位 (1-经理 2-技术 3-销售): ";
std::cin >> type;
switch(type) {
case 1:
employees.push_back(new Manager(nextId++, name));
break;
case 2: {
double hours;
std::cout << "请输入本月工时: ";
std::cin >> hours;
employees.push_back(new Technician(nextId++, name, hours));
break;
}
case 3: {
double sales;
std::cout << "请输入本月销售额: ";
std::cin >> sales;
employees.push_back(new Salesman(nextId++, name, sales));
break;
}
}
std::cout << "添加成功!" << std::endl;
}
注意事项:
- 删除员工时,记得先
delete对象再erase指针,否则内存泄漏 - 修改员工信息时,如果岗位变了,需要先删除旧对象再创建新对象
- 析构函数里要遍历容器
delete所有员工对象
项目总结与经验分享
这个项目做完,你基本就掌握了继承和多态在实际项目中的用法。我总结几个关键点:
- 纯虚函数定义接口:基类只声明做什么,不关心怎么做。子类自己决定实现细节。
- 基类指针统一管理:用
vector<Employee*>存所有员工,遍历时自动多态。 - 虚析构保证安全:这是C++里最容易踩的坑之一,我当年就吃过亏。
- 扩展性极强:如果以后要加新岗位(比如实习生、外包人员),只需要新增一个派生类,重写
calcSalary()就行,现有代码一行都不用改。
说白了,继承和多态就是让你写出「对扩展开放,对修改关闭」的代码。这个项目虽然小,但背后的设计思想,你在任何大型C++项目里都能看到它的影子。