《高级语言程序设计》作业报告
作业名称: 公司员工管理系统
学 院 专 业 学生姓名 任课教师
提交日期 2014年6月27日
一、 问题描述
一间公司有各种人员,对人员信息的管理显得比较重要。于是,本系统是要
解决公司员工信息的管理。主要有信息的增加,查询,删除,更新等操作。解决了人员的增加,减少,变更等的情况。 二、
系统设计
1、类体系设计:
设计一个员工虚基类staff ,包含编号、姓名和年龄保护数据成员,还有相关的函数。因为公司里面人员的分类众多,难以找到统一标准,在此进行简化,暂且将人员分为管理方面和研究方面。所以,从基类中派生出研究人员类engineer, 里面增加专业,职称两个保护数据成员。同样地,管理类leader 也从基类派生,里面增加职位,部门两个保护数据成员。考虑到有的员工同时具有这两个性质,即同时兼有管理和研究的职责,于是从研究类和管理类中派生出研究管理类chairman ,该类属于多继承了前面的两个类。现在已经有四个类,而且它们具有继承关系。接着要考虑对数据的操作和对各种员工的管理操作,另外定义一个员工管理类staffmanage ,将各种操作函数,数据成员进行封装。至于各个类的成员函数都有自己的版本,利用多态性,用基类指针指向派生类对象进行调用。 2、数据结构分析
因为涉及到信息的处理,所以采用二进制文件staff.dat 保存数据。上述的类体系中,不同类层次的对象具有的数据成员不同,为了方便存储在一个二进制文件中并且能进行查询等操作,另外建立索引结构indextype ,并将索引存储在索引文件index.dat 中。索引结构中必须包含一个数据成员position 记录不同对象数据在二进制文件的相对存储位置。另外,查找数据的标志设置为人员的编号num ,为了便于进行删除操作,设删除标记deltag.
最后,文件操作时要确定写入的文件大小,需要有人员类型标记stafftypeb 便于分配存储空间。 3、类定义及成员函数功能描述:
虚基类staff :
class staff {
public:
staff(){} //构造函数 virtual~staff(){} //虚析构函数 const char*getnum()const{return num;} //返回编号 virtual void input()=0; //输入函数 virtual void show()const=0; //显示数据 virtual void read(fstream &f)const=0; //读文件 virtual void write(fstream &f)const=0; //写文件 protected:
char num[8]; //编号 char name[12];//姓名 int age; //年龄 }
该基类把员工的基本数据成员和基本操作都包含进来了。除了返回编号的函数有具体实现,其他函数都声明为纯虚函数。 研究人员类engineer
class engineer:virtual public staff {
public:
engineer(){} //构造函数 virtual~ engineer(){} //虚析构函数 void input(); //输入数据 void show()const; //显示数据 void read(fstream &f)const //读文件 {
f.read((char*)this,sizeof(engineer)); };
void write(fstream &f)const //写文件 {
f.write((char*)this,sizeof(engineer)); };
protected:
char major[12]; //专业 char prof[12]; //职称 };
该类增加两个成员以记录更多的性质,函数也会给出具体实现,这里部分函数只做了声明。 管理人员类leader:
class leader:virtual public staff {
public:
leader(){}//构造函数
virtual~leader(){}//虚析构函数 void input();//输入数据
void show()const // 显示数据 { //显示信息
coutvoid read(fstream &f)const //读文件 {
f.read((char*)this,sizeof(leader)); };
void write(fstream &f)const {
f.write((char*)this,sizeof(leader)); };
protected: //数据成员 char job[12]; //职务 char dep[12]; //部门 }
同样,管理人员类也声明了函数并给出了实现,增加了职务和部门两个数据成员。
管理及研究人员类chairman :
class chairman:public engineer,public leader {
public:
chairman(){} //构造函数 virtual~chairman(){} //虚析构函数 void input(); //输入数据 void show()const // 显示数据 void read(fstream &f)const //读文件 {
f.read((char*)this,sizeof(chairman)); };
void write(fstream &f)const //写文件 {
f.write((char*)this,sizeof(chairman)); };
该类继承了engineer 类和leader, 包含前两者的数据成员并且有自己版本的函数实现。
员工管理类manage: class staffmanage {public:
staffmanage(); //构造函数 virtual~staffmanage(); //虚析构函数 void run(); //菜单函数 private: //私有成员 fstream file; //人员数据文件 indextype*indextable ; //索引表
int maxsize; //最大索引项个数 int count; //索引项个数
void addindexitem(const indextype &e); //在索引表中增加索引项 void adddata(); //增加数据 void updatedata(); //更新数据 void searchdata(); //查询数据
void deledata(); //删除数据,只作删除标记 void pack(); //在物理上删除作有删除标记的纪录
};
该类统一了对数据文件的操作。数据成员有数据文件,索引表定义为动态的,还有索引项个数的记录和一个最大索引项限制。
4、程序流程图:
三、程序测试
1、 登录模块
密码正确即可,初始密码为zxw, 有3次输入机会 2、 初始界面
菜单简单,操作方便 3、 增加数据
在测试时输入三组不同数据,操作均有提示,最后按‘q’返回主界面。
4、 查询操作
按照编号查找,找到后输出数据。 5、 删除操作:
按照编号查找,显示成功删除的操作。 6、 修改数据:
按编号查找,之后进行修改,人员类型是否改变会有不同的操作。 7、 重组数据:
为了充分利用存储空间,在数据文件中的作有删除标记的数据要被删除。 8、 退出:选择‘6’即可退出。 四、使用说明
本系统操作很简单,按照它的说明进行操作就行。先要输入密码才能登录系统。菜单的前五个功能可以反复执行。 五、程序的改进及bug:
本程序相对比较简单,很多功能都很粗糙。比如不可以修改密码,比如不可以输入其他的数据。还有,对员工分类过于简单。这些确实可以逐渐完善,鉴于系统的完成时间有限,就没有优化。调试过程中发现一个BUG ,再次打开程序查找先前输入的数据时会出现异常,异常信息如下:
问题签名:
问题事件名称: APPCRASH 应用程序名:
公司员工管理系统.exe
应用程序版本: 0.0.0.0 应用程序时间戳:
53a6719d
故障模块名称: 公司员工管理系统.exe 故障模块版本:
0.0.0.0
故障模块时间戳: 53a6719d
异常代码: c0000005 异常偏移: 0001e72d
OS 版本: 6.1.7601.2.1.0.256.1 区域设置 ID: 其他信息 1: 其他信息 2: 其他信息 3: 其他信息 4:
2052 0a9e
0a9e372d3b4ad19135b953a78882e789 0a9e
0a9e372d3b4ad19135b953a78882e789
于是我一直查找异常的原因,估计是第二次运行的时候,初始化文件时,文件数据读入文件流时的绝对位置发生了改变。尝试修改程序,但是遗憾的是直至撰写报告的时候,我还是没有解决到问题。从这个过程中我深刻地感受到自己所懂得的实在是太少了。有一个BUG 实在很遗憾。其中也有自己写程序是大局观不够,没有全盘考虑有关。 六、收获与体会
1、这次的课程设计真的充分暴露了我的不足,很多东西都要不断查资料,而且平时编程没有养成好的习惯,编写速度比较慢。还有,收获也是比较大的,特别是对于文件处理这一方面,具体的定位,读写等都有了进一步的了解。对于类体系的设计,也要求考虑很多东西,锻炼了将问题解决的能力。
2、积累了经验,懂得了要编写较大的程序时要先有一个大体的想法框架,然后逐步完成,有点像逐步求精法一样。只要大的框架没有错,后面即使有错误都只是局部的错误,容易改正。
3、锻炼了耐心,有时候小错误要找很久。甚至找几天都找不到,确实很需要静下心来
慢慢找。
4、认识到自己的不足,很多都是要查阅资料,甚至有一个BUG 没法解决,导致本系统未能完成。虽然未能解决,但是寻求解决办法的过程中也学到很多东西,特别是对tellg()、seekg()这两个函数的了解,还有一些别人的经验。
附:完整程序
// C++大作业.cpp : 定义控制台应用程序的入口点。
//
#include
#include
#include
#include
#include
#define increament 1000 //增量
using namespace std;
//员工类
class staff
{
public:
staff(){} //构造函数
virtual~staff(){} //虚析构函数
const char*getnum()const{return num;} //返回编号
virtual void input()=0; //输入函数
virtual void show()const=0; //显示数据
virtual void read(fstream &f)const=0; //读文件
virtual void write(fstream &f)const=0; //写文件
protected:
char num[8];
char name[12];
int age;
};
//研究人员类
class engineer:virtual public staff
{
public:
engineer(){} //构造函数
virtual~ engineer(){} //虚析构函数
void input() //输入数据
{ //输入相关信息
cout
cin>>num;
} cout>name; cout>age; cout>major; cout>prof; void show()const // 显示数据 { //显示信息 coutvoid read(fstream &f)const //读文件
{
f.read((char*)this,sizeof(engineer));
};
void write(fstream &f)const
{
f.write((char*)this,sizeof(engineer));
};
protected:
char major[12];
char prof[12];
};
//管理人员类
class leader:virtual public staff
{
public:
leader(){}//构造函数
virtual~leader(){}//析构函数
void input()
{ //输入相关信息
cout
cin>>num;
cout
cin>>name;
cout
cin>>age;
cout
cin>>dep;
cout
cin>>job;}
void show()const // 显示数据
{ //显示信息
cout
};
void read(fstream &f)const //读文件
{
f.read((char*)this,sizeof(leader));
};
void write(fstream &f)const
{
f.write((char*)this,sizeof(leader));
};
protected: //数据成员
char job[12]; //职务
char dep[12]; //部门
};
//管理及研究人员类
class chairman:public engineer,public leader
{
public:
chairman(){} //构造函数
virtual~chairman(){} //虚析构函数
void input()
{ //输入相关信息
cout
cin>>num;
cout>name; cout>age; cout>dep; cout>job;
cout
cin>>major;
cout
cin>>prof;
}
void show()const // 显示数据
{ //显示信息
cout
};
void read(fstream &f)const //读文件
{
f.read((char*)this,sizeof(chairman));
};
void write(fstream &f)const
{
f.write((char*)this,sizeof(chairman));
};
};
//索引结构
struct indextype
{
bool deltag; //删除标记
char num[8]; //编号
int position; //在数据文件中的相对位置
char stafftype; //人员类型
};
class staffmanage
{public:
staffmanage() //构造函数
{
ifstream indexfile("idx.dat",ios::binary); //建立输入索引文件
if(!indexfile.fail())
{ //打开文件成功
indexfile.seekg(0,ios::end); //定位
count=indexfile.tellg()/sizeof(indextype); //索引项个数
maxsize=count+increament ; //索引表最大索引项个数
indextable=new indextype[maxsize]; //为索引表分配储存空间 indexfile.seekg(0,ios::beg); //定位
int i=0; //临时变量
indexfile.read((char*)&indextable[i++],sizeof(indextype));//读记录
while(!indexfile.eof()) //文件未结束时
{
indexfile.read((char*)&indextable[i++],sizeof(indextype)); //读记录
}
indexfile.close(); //关闭文件
}
else //打开文件失败
{
count=0; //索引项个数
maxsize=count+increament; //索引表最大索引项个数
indextable=new indextype[maxsize]; //分配储存空间
}
ifstream ifile("staff.dat"); //建立输入文件
if(ifile.fail()) //打开文件失败,表示不存在文件
{
ofstream ofile("staff.dat"); //建立输出文件
if(ofile.fail()) throw("打开文件失败!"); //抛出异常
ofile.close(); //关闭文件
}
else
{
ifile.close(); //关闭文件
}
file.open("staff.dat",ios::in|ios::out|ios::binary); //以读写方式打开文件
if (file.fail()) throw("打开文件失败!"); //抛出异常
}
virtual~staffmanage() //虚析构函数
{
ofstream indexfile("idx.dat",ios::binary); //建立输出索引文件
for(int i=0;i
{
indexfile.write((char*)&indextable[i],sizeof(indextype)); //写文件
}
indexfile .close(); //关闭文件
file.close(); //关闭文件
}
void run(); //处理菜单
private: //私有成员
fstream file; //人员数据文件
indextype*indextable ; //索引表
int maxsize; //最大索引项个数
int count; //索引项个数
void addindexitem(const indextype &e); //在索引表中增加索引项
void adddata(); //增加数据
void updatedata(); //更新数据
void searchdata(); //查询数据
void deledata(); //删除数据,只作删除标记
void pack(); //在物理上删除作有删除标记的纪录
};
void staffmanage::adddata() //增加数据
{
staff*pstaff; //人员
indextype item; //索引项
item.deltag=false; //删除标记
file.seekg(0,ios::end); //定位
char answer; //临时变量
do
{
do
{
cout
cin>>item.stafftype; //输入人员类型
item.stafftype=tolower(item.stafftype);
转换为小写字母
}while(item.stafftype!='e'&&item.stafftype!='l'&&item.stafftype!='c');
if(item.stafftype=='e')
pstaff=new engineer; //分配存储空间
else if(item.stafftype =='l')
pstaff=new leader; //分配存储空间
else pstaff=new chairman; //分配存储空间
pstaff->input(); //输入数据
strcpy_s(item.num,pstaff->getnum()); //复制编号
item.position=file.tellg(); //写入数据文件的位置
addindexitem (item); //在索引表增加索引项
pstaff->write(file); //写文件
delete pstaff; //释放存储空间
cout
cin>>answer; //输入选择
}
while(answer=='y');
cout
cout
char answer1;
cin>>answer1;
if(answer1=='q')
{
system("cls");
}
}
void staffmanage::addindexitem(const indextype &e) //在索引表中增加索引项
{
if(count>=maxsize) //索引表溢出
{
maxsize=maxsize+increament; //增加索引表容量
indextype*tmpindextable=new indextype[maxsize];//临时索引表
for(int i=1;i
} { tmpindextable[i]=indextable[i]; } delete []indextable; //释放索引表的存储空间 indextable=tmpindextable; // 指向临时索引表 } indextable[count++]=e; //加入到索引表中
void staffmanage::deledata () //删除数据
{
staff*pstaff; //人员
indextype item; //索引项
item.deltag=false; //删除标记
char num[12]; //临时变量
cout
cin>>num; //输入编号
int pos; //临时变量
for(pos=0;pos
{
if(strcmp(num,indextable[pos].num)==0&&!indextable[pos].deltag) //查找索引项位置
break;
}
if(pos
{
file.seekg(indextable[pos].position,ios::beg); //定位 if(indextable[pos].stafftype=='e') pstaff=new engineer; //分配存储空间 else if(indextable[pos].stafftype=='l') pstaff=new leader; //分配存储空间 else pstaff=new chairman; //分配存储空间 pstaff->read(file); //读文件 coutshow(); //显示信息 indextable[pos].deltag=true; //置删除标记 delete pstaff; //释放存储空间 cout
char answer; //临时变量
cin>>answer; //接受输入
if(answer=='q')
{
system("cls"); //使用清屏函数
}
}
void login(int &loginsuccess) //登录函数
{
cout
cout
for (int i = 0; i
{
char code[10];
cout
cin>>code;
if (strcmp("zxw",code)==0) //判断密码是否正确
{
cout
loginsuccess=true; //给登录标志置值
break;
}
cout
}
void staffmanage::run() //数
{
int select; //码
do
{
cout
cout
cout
cout
cout
cout
cout
cout
选择操作函选择菜单号
} cin>>select; //输入选择 while(cin.get()!='\n'); switch(select) { case 1: } adddata (); //增加数据 break; updatedata(); //更新数据 break; searchdata (); //查询数据 break; deledata(); //删除数据 break; pack(); //在物理上删break; case 2: case 3: case 4: case 5: 除作有删除标记的纪录 while(select!=6); //选择6时退出
}
oid staffmanage::searchdata() //查询人员
{
staff*pstaff; //人员
char num[12]; //临时变量
cout
cin>>num; //输入编号
int pos; //人员编号
for(pos=0;pos
{
if(strcmp(num,indextable[pos].num)==0&&!indextable[pos].deltag)
break;
}
if(pos
{
file.seekg(indextable[pos].position,ios::beg); //定位
if(indextable[pos].stafftype=='e')
pstaff=new engineer; //分配存储空间
else if(indextable[pos].stafftype=='l')
pstaff=new leader; //分配存储空间 else pstaff=new chairman; //分配存储空间 pstaff->read(file); //读文件 pstaff->show(); //显示数据 delete pstaff; //删除存储空间 } else { cout>answer; //接受输入 if(answer=='q') {
system("cls"); //使用清屏函数 }
void staffmanage::updatedata () //更新数据
{
staff*pstaff; //人员 indextype item; //索引项 item.deltag=false; //删除标记 char num[12]; //临时变量 cout>num; //输入编号 int pos; //临时变量 for(pos=0;posread(file); //读文件 pstaff->show(); //显示数据 do
";
cout>item.stafftype; //输item.stafftype=tolower(item.stafftype); //转换 入人员类型
为小写字母
}while(item.stafftype!='e'&&item.stafftype!='l'&&item.stafftype!='c'); if(item.stafftype =='e') pstaff=new engineer; //分配存储空间 else if(item.stafftype =='l') pstaff=new leader; //分配存储空间 else pstaff=new chairman; //分配存储空间 pstaff->input(); //输入数据 if(item.stafftype==indextable[pos].stafftype ) { strcpy_s(indextable[pos].num,pstaff->getnum()); //复制编号 file.seekg(indextable[pos].position,ios::beg); //定位 } else { indextable[pos].deltag=true; //删除标记 strcpy_s(item.num,pstaff->getnum()); //复制编号 file.seekg(0,ios::end); //定位 item.position=file.tellg(); //写入文件的位置 addindexitem (item); //增加索引项 } pstaff->write (file); //写文件 delete pstaff; //删除存储空间 cout>answer; //接受输入 if(answer=='q') { system("cls"); //使用清屏函数 }
}
void staffmanage::pack() //重组文件 {
置
if(indextable[pos].stafftype=='e') pstaff=new engineer; //分配存储空间 else if(indextable[pos].stafftype=='l') ofstream ofile("tem.dat") ; //建立输出文件 ofile.close(); //关闭文件 fstream outfile("tem.dat",ios::app|ios::binary); //打开文件 staff*pstaff; //人员 int newcount=0; //新的索引项个数 for(int pos=0;posread(file); //读文件 pstaff->write (outfile); //写文件 delete pstaff; //删除存储空间 indextable[newcount++]=indextable[pos]; //复制索引项 } } count=newcount; // 新的索引项个数
file.close() ; //关闭文件 outfile.close(); //关闭文件 remove("staff.dat"); //移除文件 rename("tem.dat","staff.dat"); //重命名文件 file.open("staff.dat",ios::in|ios::out|ios::binary); //重新打开文件 cout
cout
char answer; //临时变量
cin>>answer; //接受输入
if(answer=='q')
{
system("cls"); //使用清屏函数 }
}
void login(int& loginsuccess); //登录系统函数
void main()
{ staffmanage objstaff; //建立员工管理对象
int loginsuccess = false; //设置登录标志
login (loginsuccess); //调用登录函数
if ( loginsuccess )
{ cout
objstaff .run (); //进入主菜单
}
else
{ system
//清屏
cout
}
("cls");
《高级语言程序设计》作业报告
作业名称: 公司员工管理系统
学 院 专 业 学生姓名 任课教师
提交日期 2014年6月27日
一、 问题描述
一间公司有各种人员,对人员信息的管理显得比较重要。于是,本系统是要
解决公司员工信息的管理。主要有信息的增加,查询,删除,更新等操作。解决了人员的增加,减少,变更等的情况。 二、
系统设计
1、类体系设计:
设计一个员工虚基类staff ,包含编号、姓名和年龄保护数据成员,还有相关的函数。因为公司里面人员的分类众多,难以找到统一标准,在此进行简化,暂且将人员分为管理方面和研究方面。所以,从基类中派生出研究人员类engineer, 里面增加专业,职称两个保护数据成员。同样地,管理类leader 也从基类派生,里面增加职位,部门两个保护数据成员。考虑到有的员工同时具有这两个性质,即同时兼有管理和研究的职责,于是从研究类和管理类中派生出研究管理类chairman ,该类属于多继承了前面的两个类。现在已经有四个类,而且它们具有继承关系。接着要考虑对数据的操作和对各种员工的管理操作,另外定义一个员工管理类staffmanage ,将各种操作函数,数据成员进行封装。至于各个类的成员函数都有自己的版本,利用多态性,用基类指针指向派生类对象进行调用。 2、数据结构分析
因为涉及到信息的处理,所以采用二进制文件staff.dat 保存数据。上述的类体系中,不同类层次的对象具有的数据成员不同,为了方便存储在一个二进制文件中并且能进行查询等操作,另外建立索引结构indextype ,并将索引存储在索引文件index.dat 中。索引结构中必须包含一个数据成员position 记录不同对象数据在二进制文件的相对存储位置。另外,查找数据的标志设置为人员的编号num ,为了便于进行删除操作,设删除标记deltag.
最后,文件操作时要确定写入的文件大小,需要有人员类型标记stafftypeb 便于分配存储空间。 3、类定义及成员函数功能描述:
虚基类staff :
class staff {
public:
staff(){} //构造函数 virtual~staff(){} //虚析构函数 const char*getnum()const{return num;} //返回编号 virtual void input()=0; //输入函数 virtual void show()const=0; //显示数据 virtual void read(fstream &f)const=0; //读文件 virtual void write(fstream &f)const=0; //写文件 protected:
char num[8]; //编号 char name[12];//姓名 int age; //年龄 }
该基类把员工的基本数据成员和基本操作都包含进来了。除了返回编号的函数有具体实现,其他函数都声明为纯虚函数。 研究人员类engineer
class engineer:virtual public staff {
public:
engineer(){} //构造函数 virtual~ engineer(){} //虚析构函数 void input(); //输入数据 void show()const; //显示数据 void read(fstream &f)const //读文件 {
f.read((char*)this,sizeof(engineer)); };
void write(fstream &f)const //写文件 {
f.write((char*)this,sizeof(engineer)); };
protected:
char major[12]; //专业 char prof[12]; //职称 };
该类增加两个成员以记录更多的性质,函数也会给出具体实现,这里部分函数只做了声明。 管理人员类leader:
class leader:virtual public staff {
public:
leader(){}//构造函数
virtual~leader(){}//虚析构函数 void input();//输入数据
void show()const // 显示数据 { //显示信息
coutvoid read(fstream &f)const //读文件 {
f.read((char*)this,sizeof(leader)); };
void write(fstream &f)const {
f.write((char*)this,sizeof(leader)); };
protected: //数据成员 char job[12]; //职务 char dep[12]; //部门 }
同样,管理人员类也声明了函数并给出了实现,增加了职务和部门两个数据成员。
管理及研究人员类chairman :
class chairman:public engineer,public leader {
public:
chairman(){} //构造函数 virtual~chairman(){} //虚析构函数 void input(); //输入数据 void show()const // 显示数据 void read(fstream &f)const //读文件 {
f.read((char*)this,sizeof(chairman)); };
void write(fstream &f)const //写文件 {
f.write((char*)this,sizeof(chairman)); };
该类继承了engineer 类和leader, 包含前两者的数据成员并且有自己版本的函数实现。
员工管理类manage: class staffmanage {public:
staffmanage(); //构造函数 virtual~staffmanage(); //虚析构函数 void run(); //菜单函数 private: //私有成员 fstream file; //人员数据文件 indextype*indextable ; //索引表
int maxsize; //最大索引项个数 int count; //索引项个数
void addindexitem(const indextype &e); //在索引表中增加索引项 void adddata(); //增加数据 void updatedata(); //更新数据 void searchdata(); //查询数据
void deledata(); //删除数据,只作删除标记 void pack(); //在物理上删除作有删除标记的纪录
};
该类统一了对数据文件的操作。数据成员有数据文件,索引表定义为动态的,还有索引项个数的记录和一个最大索引项限制。
4、程序流程图:
三、程序测试
1、 登录模块
密码正确即可,初始密码为zxw, 有3次输入机会 2、 初始界面
菜单简单,操作方便 3、 增加数据
在测试时输入三组不同数据,操作均有提示,最后按‘q’返回主界面。
4、 查询操作
按照编号查找,找到后输出数据。 5、 删除操作:
按照编号查找,显示成功删除的操作。 6、 修改数据:
按编号查找,之后进行修改,人员类型是否改变会有不同的操作。 7、 重组数据:
为了充分利用存储空间,在数据文件中的作有删除标记的数据要被删除。 8、 退出:选择‘6’即可退出。 四、使用说明
本系统操作很简单,按照它的说明进行操作就行。先要输入密码才能登录系统。菜单的前五个功能可以反复执行。 五、程序的改进及bug:
本程序相对比较简单,很多功能都很粗糙。比如不可以修改密码,比如不可以输入其他的数据。还有,对员工分类过于简单。这些确实可以逐渐完善,鉴于系统的完成时间有限,就没有优化。调试过程中发现一个BUG ,再次打开程序查找先前输入的数据时会出现异常,异常信息如下:
问题签名:
问题事件名称: APPCRASH 应用程序名:
公司员工管理系统.exe
应用程序版本: 0.0.0.0 应用程序时间戳:
53a6719d
故障模块名称: 公司员工管理系统.exe 故障模块版本:
0.0.0.0
故障模块时间戳: 53a6719d
异常代码: c0000005 异常偏移: 0001e72d
OS 版本: 6.1.7601.2.1.0.256.1 区域设置 ID: 其他信息 1: 其他信息 2: 其他信息 3: 其他信息 4:
2052 0a9e
0a9e372d3b4ad19135b953a78882e789 0a9e
0a9e372d3b4ad19135b953a78882e789
于是我一直查找异常的原因,估计是第二次运行的时候,初始化文件时,文件数据读入文件流时的绝对位置发生了改变。尝试修改程序,但是遗憾的是直至撰写报告的时候,我还是没有解决到问题。从这个过程中我深刻地感受到自己所懂得的实在是太少了。有一个BUG 实在很遗憾。其中也有自己写程序是大局观不够,没有全盘考虑有关。 六、收获与体会
1、这次的课程设计真的充分暴露了我的不足,很多东西都要不断查资料,而且平时编程没有养成好的习惯,编写速度比较慢。还有,收获也是比较大的,特别是对于文件处理这一方面,具体的定位,读写等都有了进一步的了解。对于类体系的设计,也要求考虑很多东西,锻炼了将问题解决的能力。
2、积累了经验,懂得了要编写较大的程序时要先有一个大体的想法框架,然后逐步完成,有点像逐步求精法一样。只要大的框架没有错,后面即使有错误都只是局部的错误,容易改正。
3、锻炼了耐心,有时候小错误要找很久。甚至找几天都找不到,确实很需要静下心来
慢慢找。
4、认识到自己的不足,很多都是要查阅资料,甚至有一个BUG 没法解决,导致本系统未能完成。虽然未能解决,但是寻求解决办法的过程中也学到很多东西,特别是对tellg()、seekg()这两个函数的了解,还有一些别人的经验。
附:完整程序
// C++大作业.cpp : 定义控制台应用程序的入口点。
//
#include
#include
#include
#include
#include
#define increament 1000 //增量
using namespace std;
//员工类
class staff
{
public:
staff(){} //构造函数
virtual~staff(){} //虚析构函数
const char*getnum()const{return num;} //返回编号
virtual void input()=0; //输入函数
virtual void show()const=0; //显示数据
virtual void read(fstream &f)const=0; //读文件
virtual void write(fstream &f)const=0; //写文件
protected:
char num[8];
char name[12];
int age;
};
//研究人员类
class engineer:virtual public staff
{
public:
engineer(){} //构造函数
virtual~ engineer(){} //虚析构函数
void input() //输入数据
{ //输入相关信息
cout
cin>>num;
} cout>name; cout>age; cout>major; cout>prof; void show()const // 显示数据 { //显示信息 coutvoid read(fstream &f)const //读文件
{
f.read((char*)this,sizeof(engineer));
};
void write(fstream &f)const
{
f.write((char*)this,sizeof(engineer));
};
protected:
char major[12];
char prof[12];
};
//管理人员类
class leader:virtual public staff
{
public:
leader(){}//构造函数
virtual~leader(){}//析构函数
void input()
{ //输入相关信息
cout
cin>>num;
cout
cin>>name;
cout
cin>>age;
cout
cin>>dep;
cout
cin>>job;}
void show()const // 显示数据
{ //显示信息
cout
};
void read(fstream &f)const //读文件
{
f.read((char*)this,sizeof(leader));
};
void write(fstream &f)const
{
f.write((char*)this,sizeof(leader));
};
protected: //数据成员
char job[12]; //职务
char dep[12]; //部门
};
//管理及研究人员类
class chairman:public engineer,public leader
{
public:
chairman(){} //构造函数
virtual~chairman(){} //虚析构函数
void input()
{ //输入相关信息
cout
cin>>num;
cout>name; cout>age; cout>dep; cout>job;
cout
cin>>major;
cout
cin>>prof;
}
void show()const // 显示数据
{ //显示信息
cout
};
void read(fstream &f)const //读文件
{
f.read((char*)this,sizeof(chairman));
};
void write(fstream &f)const
{
f.write((char*)this,sizeof(chairman));
};
};
//索引结构
struct indextype
{
bool deltag; //删除标记
char num[8]; //编号
int position; //在数据文件中的相对位置
char stafftype; //人员类型
};
class staffmanage
{public:
staffmanage() //构造函数
{
ifstream indexfile("idx.dat",ios::binary); //建立输入索引文件
if(!indexfile.fail())
{ //打开文件成功
indexfile.seekg(0,ios::end); //定位
count=indexfile.tellg()/sizeof(indextype); //索引项个数
maxsize=count+increament ; //索引表最大索引项个数
indextable=new indextype[maxsize]; //为索引表分配储存空间 indexfile.seekg(0,ios::beg); //定位
int i=0; //临时变量
indexfile.read((char*)&indextable[i++],sizeof(indextype));//读记录
while(!indexfile.eof()) //文件未结束时
{
indexfile.read((char*)&indextable[i++],sizeof(indextype)); //读记录
}
indexfile.close(); //关闭文件
}
else //打开文件失败
{
count=0; //索引项个数
maxsize=count+increament; //索引表最大索引项个数
indextable=new indextype[maxsize]; //分配储存空间
}
ifstream ifile("staff.dat"); //建立输入文件
if(ifile.fail()) //打开文件失败,表示不存在文件
{
ofstream ofile("staff.dat"); //建立输出文件
if(ofile.fail()) throw("打开文件失败!"); //抛出异常
ofile.close(); //关闭文件
}
else
{
ifile.close(); //关闭文件
}
file.open("staff.dat",ios::in|ios::out|ios::binary); //以读写方式打开文件
if (file.fail()) throw("打开文件失败!"); //抛出异常
}
virtual~staffmanage() //虚析构函数
{
ofstream indexfile("idx.dat",ios::binary); //建立输出索引文件
for(int i=0;i
{
indexfile.write((char*)&indextable[i],sizeof(indextype)); //写文件
}
indexfile .close(); //关闭文件
file.close(); //关闭文件
}
void run(); //处理菜单
private: //私有成员
fstream file; //人员数据文件
indextype*indextable ; //索引表
int maxsize; //最大索引项个数
int count; //索引项个数
void addindexitem(const indextype &e); //在索引表中增加索引项
void adddata(); //增加数据
void updatedata(); //更新数据
void searchdata(); //查询数据
void deledata(); //删除数据,只作删除标记
void pack(); //在物理上删除作有删除标记的纪录
};
void staffmanage::adddata() //增加数据
{
staff*pstaff; //人员
indextype item; //索引项
item.deltag=false; //删除标记
file.seekg(0,ios::end); //定位
char answer; //临时变量
do
{
do
{
cout
cin>>item.stafftype; //输入人员类型
item.stafftype=tolower(item.stafftype);
转换为小写字母
}while(item.stafftype!='e'&&item.stafftype!='l'&&item.stafftype!='c');
if(item.stafftype=='e')
pstaff=new engineer; //分配存储空间
else if(item.stafftype =='l')
pstaff=new leader; //分配存储空间
else pstaff=new chairman; //分配存储空间
pstaff->input(); //输入数据
strcpy_s(item.num,pstaff->getnum()); //复制编号
item.position=file.tellg(); //写入数据文件的位置
addindexitem (item); //在索引表增加索引项
pstaff->write(file); //写文件
delete pstaff; //释放存储空间
cout
cin>>answer; //输入选择
}
while(answer=='y');
cout
cout
char answer1;
cin>>answer1;
if(answer1=='q')
{
system("cls");
}
}
void staffmanage::addindexitem(const indextype &e) //在索引表中增加索引项
{
if(count>=maxsize) //索引表溢出
{
maxsize=maxsize+increament; //增加索引表容量
indextype*tmpindextable=new indextype[maxsize];//临时索引表
for(int i=1;i
} { tmpindextable[i]=indextable[i]; } delete []indextable; //释放索引表的存储空间 indextable=tmpindextable; // 指向临时索引表 } indextable[count++]=e; //加入到索引表中
void staffmanage::deledata () //删除数据
{
staff*pstaff; //人员
indextype item; //索引项
item.deltag=false; //删除标记
char num[12]; //临时变量
cout
cin>>num; //输入编号
int pos; //临时变量
for(pos=0;pos
{
if(strcmp(num,indextable[pos].num)==0&&!indextable[pos].deltag) //查找索引项位置
break;
}
if(pos
{
file.seekg(indextable[pos].position,ios::beg); //定位 if(indextable[pos].stafftype=='e') pstaff=new engineer; //分配存储空间 else if(indextable[pos].stafftype=='l') pstaff=new leader; //分配存储空间 else pstaff=new chairman; //分配存储空间 pstaff->read(file); //读文件 coutshow(); //显示信息 indextable[pos].deltag=true; //置删除标记 delete pstaff; //释放存储空间 cout
char answer; //临时变量
cin>>answer; //接受输入
if(answer=='q')
{
system("cls"); //使用清屏函数
}
}
void login(int &loginsuccess) //登录函数
{
cout
cout
for (int i = 0; i
{
char code[10];
cout
cin>>code;
if (strcmp("zxw",code)==0) //判断密码是否正确
{
cout
loginsuccess=true; //给登录标志置值
break;
}
cout
}
void staffmanage::run() //数
{
int select; //码
do
{
cout
cout
cout
cout
cout
cout
cout
cout
选择操作函选择菜单号
} cin>>select; //输入选择 while(cin.get()!='\n'); switch(select) { case 1: } adddata (); //增加数据 break; updatedata(); //更新数据 break; searchdata (); //查询数据 break; deledata(); //删除数据 break; pack(); //在物理上删break; case 2: case 3: case 4: case 5: 除作有删除标记的纪录 while(select!=6); //选择6时退出
}
oid staffmanage::searchdata() //查询人员
{
staff*pstaff; //人员
char num[12]; //临时变量
cout
cin>>num; //输入编号
int pos; //人员编号
for(pos=0;pos
{
if(strcmp(num,indextable[pos].num)==0&&!indextable[pos].deltag)
break;
}
if(pos
{
file.seekg(indextable[pos].position,ios::beg); //定位
if(indextable[pos].stafftype=='e')
pstaff=new engineer; //分配存储空间
else if(indextable[pos].stafftype=='l')
pstaff=new leader; //分配存储空间 else pstaff=new chairman; //分配存储空间 pstaff->read(file); //读文件 pstaff->show(); //显示数据 delete pstaff; //删除存储空间 } else { cout>answer; //接受输入 if(answer=='q') {
system("cls"); //使用清屏函数 }
void staffmanage::updatedata () //更新数据
{
staff*pstaff; //人员 indextype item; //索引项 item.deltag=false; //删除标记 char num[12]; //临时变量 cout>num; //输入编号 int pos; //临时变量 for(pos=0;posread(file); //读文件 pstaff->show(); //显示数据 do
";
cout>item.stafftype; //输item.stafftype=tolower(item.stafftype); //转换 入人员类型
为小写字母
}while(item.stafftype!='e'&&item.stafftype!='l'&&item.stafftype!='c'); if(item.stafftype =='e') pstaff=new engineer; //分配存储空间 else if(item.stafftype =='l') pstaff=new leader; //分配存储空间 else pstaff=new chairman; //分配存储空间 pstaff->input(); //输入数据 if(item.stafftype==indextable[pos].stafftype ) { strcpy_s(indextable[pos].num,pstaff->getnum()); //复制编号 file.seekg(indextable[pos].position,ios::beg); //定位 } else { indextable[pos].deltag=true; //删除标记 strcpy_s(item.num,pstaff->getnum()); //复制编号 file.seekg(0,ios::end); //定位 item.position=file.tellg(); //写入文件的位置 addindexitem (item); //增加索引项 } pstaff->write (file); //写文件 delete pstaff; //删除存储空间 cout>answer; //接受输入 if(answer=='q') { system("cls"); //使用清屏函数 }
}
void staffmanage::pack() //重组文件 {
置
if(indextable[pos].stafftype=='e') pstaff=new engineer; //分配存储空间 else if(indextable[pos].stafftype=='l') ofstream ofile("tem.dat") ; //建立输出文件 ofile.close(); //关闭文件 fstream outfile("tem.dat",ios::app|ios::binary); //打开文件 staff*pstaff; //人员 int newcount=0; //新的索引项个数 for(int pos=0;posread(file); //读文件 pstaff->write (outfile); //写文件 delete pstaff; //删除存储空间 indextable[newcount++]=indextable[pos]; //复制索引项 } } count=newcount; // 新的索引项个数
file.close() ; //关闭文件 outfile.close(); //关闭文件 remove("staff.dat"); //移除文件 rename("tem.dat","staff.dat"); //重命名文件 file.open("staff.dat",ios::in|ios::out|ios::binary); //重新打开文件 cout
cout
char answer; //临时变量
cin>>answer; //接受输入
if(answer=='q')
{
system("cls"); //使用清屏函数 }
}
void login(int& loginsuccess); //登录系统函数
void main()
{ staffmanage objstaff; //建立员工管理对象
int loginsuccess = false; //设置登录标志
login (loginsuccess); //调用登录函数
if ( loginsuccess )
{ cout
objstaff .run (); //进入主菜单
}
else
{ system
//清屏
cout
}
("cls");