1、 C++课程实践报告(企业职工工资管理系统) 27 2020年4月19日 资料内容仅供参考,如有不当或者侵权,请联系本人改正或者删除。 中南大学 本科生课程设计(实践)任务书、 设计报告 ( C++应用基础课程设计) 题 目 企业职工工资管理系统 学生学号 学生姓名指导教师 学 院 物理学院 专业班级 指导老师 计算机基础教学实验中心 07月09日 企业职工工资管理系统 摘要: 在VC++环境下编写一个基于控制台方式( Win32 Console
2、 Application) 的工资管理系统, 以实现简单地处理一个月内某企业职工工资信息。 关键词: 工资管理, 基本工资, 个人所得税。 1.企业工资管理系统开发设计思想 对于一个管理系统而言, 主函数, 函数以及成员函数是其重要组成部分。系统开发设计也是从该三方面入手, 下面加以详细阐述。 ( 1) 主函数的设计 在做一个系统开发前, 一定要明确系统的功能以及功能实现时的输出( 屏幕显示) 。编写主函数的主要任务就是确定调用函数以及控制屏幕显示。 ①确定调用的函数 根据要求, 该系统至少应该实现五种基本功能: 输出工作信息, 删除工资信息, 修改工资信息, 查找工资信息, 列
3、出所有信息。实现以上任何一种功能都必须要调用一个函数, 根据标识符的定义规则, 依次命名为AddNew(),DoDelete(),DoMotify(),DoFind(),List(). ②屏幕显示 一个系统要想处理信息, 首先必须要输出菜单及提示信息, 经过用户在键盘上的输入来选择某个功能。本系统的屏幕显示如上。 为实现该屏幕显示, 输出语句完全能够放在main()函数中, 但为了使主函数清晰明了, 我设计了一个菜单函数Main()供其调用。 (2)函数的设计 编写函数的目的就是编写一个能实现某种功能的函数供主函数调用。根据C++面向对象的特点, 函数也能够调用类中的成员函数
4、这样主函数, 函数以及成员函数之间的层次分明, 关系就清晰明了, 不会有冗长的感觉。函数设计的主要任务是确定调用的成员函数以及屏幕显示。 ①确定调用的成员函数。 不同的函数调用的成员函数是不尽相同的, 基本上每个函数都有一个对应的成员函数, 例如AddNew()与AddItem(),DoDelete()与RemoveItem(),DoFind()与Search( ) ,DoMotify()与Replace(),List()与Worker.List()对应, 这些成员函数都是共有函数, 而且只被其对应函数唯一调用一次。当然, 每个函数不可能只调用一个成员函数, 例如AddNew()还调用了
5、另外两个函数Input( ) 和Actualpay()。 ②屏幕显示 编写函数也需要控制输出以及功能间的转换, 从而每一个函数都需要有一个循环来控制其结束。结束的条件都是”当输入的编号为-1时结束”, 循环语句有while也有do…while, 例如DoDelete()和DoFind()用的是do…while, AddNew()用到的是while语句。 ( 3) 成员函数的设计。 成员函数是系统的灵魂, 因为所有的处理过程的细节都在成员函数中完成的。编写成员函数实际上就是一个算法的实现。成员函数的设计包括两方面内容: 成员函数算法的实现和成员函数过程的实现。 ①成员函数算法的实现
6、工资管理系统不能单凭数组来处理数据, 因为企业职工数是不确定的, 而且数组在删除和查找某条信息是相当繁琐。因此该系统需要一个全新的数据处理方式——链表。链表是最简单也是最常见的一种动态数据结构, 它是对动态获得的内存进行组织的一种结构。它不需要实现定义固定的长度, 灵活性更强。 链表是算法的关键。在添加新的数据时, 能够表头插入也能够表尾插入, 这两种插入方法决定了其它成员函数数据的处理。本系统中采取的是表尾插入的方法。在删除某信息时需要判断数据是在表头, 表中还是表尾, 如果删除的是在表中, 则需要将删除的前后链表连接起来。总之, 本系统大量运用了链表的5种基本操作: 建立链表、 链表的插
7、入、 删除、 输入和查找。 ②成员函数过程的实现 算法确定后还需要控制屏幕显示、 条件的判断以及调用其它成员函数。成员函数之间是能够相互调用的, 例如成员函数List()就调用了成员函数ListCount()来统计当前链表信息的总数, 同时还调用了成员函数Print( ) 来输出Worker_pay()的信息。整个过程中还有一个重要的指针, Worker_pay *Find(),它被Search(), RemoveItem()以及AddItem()所调用。其次成员函数中大量运用到了程序控制结构。例如, AddItem()中用if来判断是否是链表的表头, List()中用到了while语句来
8、实现循环输出。最后屏幕上则需要显示一些完成了某种功能的标志, 例如”成功删除编号为xx的信息”, ”成功修改编号为xx的信息”等。 ( 3) 系统结构框架 系统的结构框架主要是系统的流程图以及函数之间的调用关系, 该图能描述系统清晰准确的表现出系统的功能实现。 职工工资管理系统结构框架职工工资管理系统 图 输出主菜单 输入选项 添加职工工资信息 删除职工工资信息 修改职工工资信息 输出全体职工工资信息 输出指定职工工资信息 结束 退出 RemovrItem() .List() Search() R
9、eplace() AddItem() DoFind() List() DoMotify() DoDelete() AddNew() 2企业职工工资管理系统功能及系统设计介绍 该工资管理系统能够分为5个模块, 每个模块都有其对应的功能以及其设计。下面对系统的功能和模块的实现进行简要分析。 ( 1) 输入模块 输入模块的功能是创立存储职工工资信息的存储系统以及添加某职工的工资信息。其中的信息包括职工编号, 基本工资, 津贴, 房租, 交通费以及银行储蓄。为实
10、现输入的功能, 有两个方面的任务: 定义结构体以及建立链表。 ①定义结构体 结构体的名称为Worker_pay,其中包含的信息有职工编号( num) , 基本工资(pay[0]), 津贴(pay[1]), 房租(pay[2]), 交通费(pay[3]),储蓄(pay[4])以及个人所得税(tax),应扣数( deduct) ,实发数(actualpay)。定义一个pay的数组时为了简化变量的定义, 使程序更有条理。 ②建立链表 经过从表尾插入的方法来建立链表, 首先要先设立一个头指针( head) 来存放链表的首地址。然后, 不断用new运算符生
11、成一个新的起点, 将这个起点链入已有的链表尾部; 如果链表中还没有结点, 则这个新结点将是首结点, 否则, 将新结点的地址赋给原有链表的尾结点的next指针。 ( 2) 删除模块 删除模块的功能是删除某职工的工资信息。当然, 信息包括所有输入的信息, 以及程序内部函数计算的信息例如个人所得税, 实发数。 从一个链表中删去一个结点, 首先从表头开始, 找到被删结点后, 只要改变链接关系即可, 使被删结点的前去结点的指针域指向被删结点的后继结点。如果删去的结点是首结点, 则将第二个结点的地址作为新的链表的首地址返回; 如果删去的结点是链尾, 则将被删结点的前驱作为新的链尾。 ( 3) 修改
12、模块 修改模块的功能是修改某职工的部分工资信息。 要修改某职工的信息首先必须从表头开始搜寻, 当找到指定的编号是, 重新对其赋值即可。 ( 4) 查找模块 查找模块的功能就是输出指定编号职工的工资信息。 查找链表中的信息时比较简单的, 在上面的模块中也用到了, 主要是注意查找叶必须从表头开始。 ( 5) 列表模块 列表模块的功能是输出当月全体职工的工资信息。 列表模块就是依次输出链表中各结点的数据。首先要知道链表头结点的地址, 也就是head的值, 然后设一个指针变量p, 先指向第一个结点, 输出p所指结点的数据与的值, 然后使p后移一个结点, 再输出其数据与的值; 依链表顺序
13、而行, 依次输出相应结点数据域的值, 直到链表的尾结点。 ( 5) 调试过程中遇到的主要问题及解决办法 ①设计初期, 先完成初步构思, 写出主函数。然后对主函数所涉及的各个模块进行编程, 将各个模块利用指针和链表联系起来。在环境中进行调试, 应一边编译, 一边调试, 而且要一个模块一个模块的调试。直至此模块完全没有错误时, 在进入下一模块的调试。不能直接输入全部的代码一次性调, 这样错误会很多, 而且不易找出和修改。在完成程序的编译链接后, 要用多组数据进行审查, 确保做到系统无误。 设计过程中, 不应忽视环境提示的警告, 有时程序运行不正确与警告也有很大的关系。这次设计中遇到很多问题
14、都是提示类型不匹配, 这时就要认真检查前面的代码, 及时改正而且认真仔细, 杜绝此类错再次发生。 编写代码时应该少用全局变量, 全局变量在编写试看似定义次数少, 很方便。但全局变量出错几率较大, 且不易修改, 每次修改时都要全面考虑, 因此应避免用到。 程序调试中碰到的错误能够使自己学到知识。养成良好的编程习惯, 能够节省很多时间, 避免很多不必要的错误。 ②在编辑完整个程序后, 进行调试阶段总是会数显head无定义。 解决办法: 再类的定义是忘记声明指针Worker_pay *head;。 3总结 经过两周的C++课程实践, 我对C++语言设计有了一个更深, 更全面的了解,
15、特别体会到了C++面向对象操作对简化程序的重要作用。下面是我的几点体会: ①刚拿到课题时, 我一脸的茫然, 看到如此庞大的工程, 不知如何下手。这个工资管理系统中职工子信息竟然包含15条, 以前从来没有遇到过如此多的变量。和同学讨论很久好, 我发现其实能够化繁为简的, 信息中15条不一定全都要, 因为其中本身就有重复的, 例如津贴和补贴。而且能够有一个pay的数组来处理数据。因此做任何事情都必须要开动脑筋, 积极思考, 有时还要学会化繁为简。 ②在编程时条理清晰是至关重要的。主函数, 函数, 成员函数之间的层次关系, 调用关系一定要有一个全面的把握, 特别要体会类的封装性。另外很重要的一
16、点就是一定要对链表的五种操作熟练的掌握。
③在编译, 链接, 调试的过程中一定要有耐心。因为一个程序中会有很多小的错误, 甚至有的问题要几个小时才能解决。遇到问题, 一定要全面分析, 有时候还要向同学请教。总得来说, 编程时极需要耐心的。
总之, C++课程设计实践为我们提供了一个综合运用所学知识, 解决实际问题的平台, 增强了我们实践动手的能力和工程实践能力, 而且锻炼和培养了我们的自学能力, 让我们对C++有了一个更全面的了解。
附源代码:
#include
17、 struct Worker_pay { int num; float pay[5],basepay,tax,deduct,Actualpay; Worker_pay *next; }; class Worker { private: Worker_pay *head; void Print(Worker_pay *); Worker_pay *Find(int); public: Worker(){head=NULL;} int ListCount(); void AddItem(int
18、 num,float pay[5]); void RemoveItem(int); void Replace(int); void List(); void Search(int); void Actualpay(); }; int Worker::ListCount () { if(!head)return 0; Worker_pay *p=head; int n=0; while(p){n++;p
19、p->next;} return n; } void Worker::AddItem (int num,float pay[5]) { if(!head) { head=new Worker_pay; for(int i=0;i<5;i++) head->pay[i]=pay[i]; head->num=num; head->next=NULL; return; } Worker_pay *t=head; while(t&&t->num!=num) t=t->next; if(t) { cou
20、t<<"操作失败; 职工编号为"<
21、ker_pay *t=Find(num);
if(!t) return;
Worker_pay *p=head;
if(head==t)
{
head=head->next;
delete p;
cout<<"成功删除职工编号为"< 22、信息!"< 23、p)
{
cout.precision(8);
cout< 24、0)
{
cout<<"当前列表为空, 请先输入数据!"< 25、"< 26、le(p)
{
if(p->num==num) break;
p=p->next;
}
if(!p)
{
cout<<"错误: 找不到该信息! \n";
return NULL;
}
return p;
}
void Worker::Actualpay ()
{
if (ListCount()==0)
{
cout<<"当前列表为空, 请先输入数据!"< 27、pay[0]<=800)p->tax=0;
else if(p->pay[0]<= ) p->tax=(p->pay[0]-800)*0.05;
else if(p->pay[0]<=5000) p->tax=60+(p->pay[0]- )*0.1;
else p->tax=360+(p->pay[0]-5000)*0.2;
p->basepay=p->pay[0]+p->pay[1];
p->deduct=p->tax+p->pay[2]+p->pay[3];
p->Actualpay=p->pay[0]+p->pay[1]-p->tax-p->pa 28、y[2]-p->pay[3];
p=p->next;
}
return;
}
Worker Worker;
int Menu()
{
cout<<"\n*******主菜单*******"< 29、"< 30、t *num,float pay[5])
{
cout<<"请输入\t职工编号基本工资( 元) 津贴房租交通费银行储蓄"< 31、nput(&num,pay);
while(num!=-1)
{
Worker.AddItem(num,pay);
Worker.Actualpay();
Input(&num,pay);
}
return;
}
void DoFind()
{
int num;
cout< 32、
}while(num!=-1);
return;
}
void DoDelete()
{
cout< 33、当输入的职工编号为-1是表示结束输入"< 34、
while(1)
{
select=Menu();
switch(select)
{
case 0:
s=Exit();
if(s=='y'||s=='Y')return 0;
break;
case 1:
AddNew();
break;
case 2:
DoDelete();
break;
case 3:
DoMotify();
break;
case 4:
DoFind();
break;
case 5:
List();
break;
default:
cout<<"无效输入! "<






