资源描述
电子科技大学计算机学院
标 准 实 验 报 告
(实验)课程名称:C++程序设计实验
电子科技大学教务处制表
电 子 科 技 大 学
实 验 报 告
学生姓名: 学 号: 指导教师:丘志杰
实验地点:主楼A2-412 实验时间:2012.11.23
一、实验室名称:电子科技大学计算机实验教学示范中心
二、实验项目名称:C++程序设计实验
三、实验学时:24学时
四、实验原理:
了解数据封装的作用和实现方式,使用C++语言的抽象数据类型实现数据封装。了解继承的实现方式,使用C++语言的基类和派生类实现继承功能。了解运算符重载的机制,学会进行运算符重载。了解继承和多态的作用和实现方式,掌握动态联编方法,使用C++语言的抽象类和派生类实现继承性。
五、实验目的:
1、 掌握C++编程规范;
2、 掌握C++的封装、继承、运算符重载以及多态程序的基本编写方法;
3、 熟悉在visual Studio 2010(及以上版本)环境下的C++软件开发和调试过程。
六、实验内容:
C++编辑和编译系统采用Visual Studio 2010,设计1个综合运用数据封装、继承、运算符重载、多态等机制的C++编程语言的应用实验“学校教职工工资管理程序”:对学校教职工进行关系划分;着重应用数据封装、继承等机制对各类人员进行类封装并体现继承和派生关系;着重应用虚函数机制,实现计算职工工资的功能;重载“<<”运算符,能够对对象进行信息输出。
七、实验器材(设备、元器件):
1.硬件平台:
【电脑型号 戴尔 System Inspiron N4110 笔记本电脑】
【处理器 英特尔 第二代酷睿 i3-2350M @ 2.30GHz 双核】
速度 2.30 GHz (100 MHz x 23.0)
处理器数量 核心数: 2 / 线程数: 4
核心代号 Sandy Bridge NB
生产工艺 32 纳米
插槽/插座 Socket G2 (PGA 988 / BGA 1023)
一级数据缓存 2 x 32 KB, 8-Way, 64 byte lines
一级代码缓存 2 x 32 KB, 8-Way, 64 byte lines
二级缓存 2 x 256 KB, 8-Way, 64 byte lines
三级缓存 3 MB, 12-Way, 64 byte lines
特征 MMX, SSE, SSE2, SSE3, SSSE3, SSE4.1, SSE4.2, HTT, EM64T, EIST
【主板 戴尔 03NKW8 (英特尔 HM67 芯片组)】
板载设备 Intel(R) Extreme Graphics 3 Controller / 视频设备 (启用)
板载设备 Intel(R) Azalia Audio Device / 音频设备 (启用)
BIOS 戴尔 Inc. A11
制造日期 02/09/2012
【内存 4 GB ( 三星 DDR3 1333MHz )】
DIMM 0: 三星 DDR3 1333MHz 2GB
制造日期 2012 年 02 月
型号 CE M471B5773CHS-CH9
序列号: 10021220
DIMM 2: 三星 DDR3 1333MHz 2GB
制造日期 2011 年 06 月
型号 CE M471B5773DH0-CH9
序列号: 0DE93D67
【主硬盘 西数 WDC WD5000LPVX-22V0TT0 ( 500 GB / 5400 转/分 )】
硬盘已使用 共 273 次,累计 867 小时
固件 01.01A01
接口 SATA III
数据传输率 600 MB/秒
特征 S.M.A.R.T, APM, 48-bit LBA, NCQ
【显卡 ATI Radeon HD 6630M ( 1 GB / 戴尔 )】
显卡 英特尔 HD Graphics Family
显存 1803 MB
制造商 戴尔
BIOS日期 01/18/20
驱动版本 9.3.0.0
驱动日期 20121025
主显卡 ATI Radeon HD 6630M
显存 1 GB
制造商 戴尔
2.软件平台:
【操作系统 Windows 8 专业版 64位 ( DirectX 11 )】
系统安装日期 Windows 8 / 2013 年 09 月 10 日
【开发环境Microsoft Visual Studio Express 2012 for Windows Desktop】
版本 11.0.50727.42 VSLRSTAGE
Microsoft .NET Framework
版本 4.5.50709
已安装的版本: Desktop Express
Team Explorer for Visual Studio 2012 05695-004-0030004-02119
Microsoft Team Explorer for Visual Studio 2012
Visual Basic 2012 05695-004-0030004-02119
Microsoft Visual Basic 2012
Visual C# 2012 05695-004-0030004-02119
Microsoft Visual C# 2012
Visual C++ 2012 05695-004-0030004-02119
Microsoft Visual C++ 2012
NuGet 程序包管理器 2.0.30717.9005
SQL Server Data Tools 11.1.20828.01
Microsoft SQL Server Data Tools
八、实验步骤:
1. 了解实验室可用的软硬件开发平台并学习必要的知识,安装并掌握Visual Studio 2010的基本使用方法;
2. 设计和编辑学校教职工工资管理程序
(1) 对教职工进行人员划分,设计类关系图,设计每个类的成员构成;
(2) 在Visual Studio 2010环境下,对各类教职工进行数据封装,并应用继承和派生机制实现类的继承功能;
(3) 应用虚函数机制,设计计算职工工资的功能,并在Visual Studio 2010环境下实现该功能;
(4) 应用运算符重载机制,在Visual Studio 2010环境下实现对“<<”运算符的重载,能够对对象进行信息输出。
3. 编译和调试
(1) 编译相应的C++程序,若不通过,则检查出错原因;
(2) 在编译通过的情况下,调试程序,看运行结果是否与预期一致。通过单步或函数级跟进调试程序;
4. 美化和优化程序编写规范和结果显示形式
5. 截取实验结果图和撰写实验报告
九、实验数据及结果分析:
1. 实验中采用的默认数据(在程序开始时会显示并且提供了可修改的接口):
CAA(A级行政人员提成):100
CAB(B级行政人员提成):100
CAS(行政人员工龄工资):100
CTS(教师工龄工资):100
TI1(讲师课时费):10
TI2(副教授课时费):20
TI3(教授课时费):30
TI4(博导课时费):40
MS(带研究生提成):50
PHD(带博士生提成):100
2. 类说明:
CSaff:员工基础类,有姓名、工号、工龄、性别、基本工资;
CTempStaff:临时工,在员工基础上增加临时工工资;
CAdministrator:行政人员,在员工基础上增加“一般、A、B”3个职务等级 其中B级最高;
CTeacher:教师,在员工基础上增加“讲师、副教授、教授、博导”4个职务等级,增加“课时、带博士生数、带硕士生数”3方面信息。
每个类都重载了<<函数。
所有数据可增加、修改、删除、查询、磁盘读写(默认路径"F:\\staff.txt")。
3. 【第一步】初始化测试。实验开始,程序提示正在初始化,自动加载F盘下staff.txt中数据:
(类标志、姓名、工号、性别、职务等级、工龄、临时工工资、课时、硕士生数、博士生数)
1 meng 2013 M 0 20 1600 200 0 0 0
3 dsaf 20 F 博导 2 40100 0 200 10 20
3 fd 213 F 副教授 42 14142 0 20 10 0
2 sdf 21 F 一般 20 7000 0 0 0 0
加载后可根据工号(保证唯一)查询信息。
询问是否需要修改默认数据,选择N,不修改。如附录截图1所示。
【第二步】界面测试。程序进入欢迎界面,提供5个选项:1-增加 2-修改 3-删除 4-查询5-存盘退出。如附录截图1所示。
【第三步】查询测试。输入4。程序要求输入查询员工的ID,输入2013。程序立即给出了2013工号对应的员工所有信息。如附录截图1所示。
【第四步】增加测试。程序自动回到5项选择界面。输入1。提示输入基本信息,根据要求输入了姓名:刘ABC 性别:F 工号:2012050020001 工龄:10 基础工资:2000。提示输入职位:1-临时工 2-行政人员 3-教师,输入了3。提示输入教师职称:1-讲师 2-教授 3-副教授 4-博导,输入了4。提示输入授课时间、所带硕士生数、所带博士生数,输入了200 10 20,程序提示增加成功。如附录截图2所示。
【第五步】删除测试。程序自动回到5项选择界面。输入3。提示输入要删除的员工ID,输入2013。程序立即给出了对应工号的员工所有信息,提示是否删除,输入Y。提示删除成功。如附录截图3所示。
【第六步】修改测试。程序自动回到5项选择界面。输入2。提示输入要修改的员工ID。输入21。程序立即给出了对应工号的员工所有信息,并且提供了3个选项供修改:1-姓名 2-性别 3-工龄,输入1。提示输入新姓名,输入王三。提示修改成功。如附录截图4所示。
【第七步】存盘测试。程序自动回到5项选择界面。输入5。程序自动退出。检查F盘下staff.txt文件可以看到如下数据:
3 dsaf 20 F 博导 2 40100 0 200 10 20
3 刘ABC 2012050020001 F 博导 10 2000 0 200 10 20
3 fd 213 F 副教授 42 14142 0 20 10 0
2 王三 21 F 一般 20 7000 0 0 0 0
可以看见新增了“刘ABC“员工的信息,删除了”meng”员工的信息,修改了”21“工号员工的姓名,程序测试成功。如附录截图5所示。
十、实验结论:
程序实现了一个程序实现学校教职工的工资管理,根据相应计算方式设计了类,重载了<<运算符,并且实现了教职工信息的增加、修改、删除、查询、以及持久化到磁盘中等基本要求。同时,程序还增加了判断,保证了工号的唯一性,优化了数据结构,提升了程序的稳定性、优化了时空复杂度。程序提供了比较好的人机交互界面,用户能根据提示管理整个系统。
十一、总结及心得体会:
这次实验我学习了很多东西:
1. 首先遇到的问题是类的实现。由于不熟练,查询了大量的资料才得以编程,建立了类的继承关系,理清了工资计算方式,实现了封装等操作。
2. 重载运算符。由于C++书上没有<<重载的相关代码,而<<重载的步骤和普通+-重载不同,极为复杂,需要用到友元类,经过上网查询、请教老师同学、比较完善地重载了<<运算符。
3. Map相关。在考虑采用数据结构存储中,首先想到了数组和普通链表,但是由于数组时间复杂度高,空间无法扩展,普通链表操作难度大,时间复杂度也很高。我考虑了采用STL中的map,map能产生键值对应的关系,而工号正好是满足要求的key。同时,map采用的是一种非常高效的非严格意义上的平衡检索二叉树:红黑树(red-black tree),基本上所有操作都是O(log2n),而且能够自动扩容,提供了大量接口函数,极为方便稳定快捷。因此我采用了map来存储数据。STL操作中遇到了一个有意思的问题:就是释放内存。由于类里面没有数组等数据结构,因此用默认析构函数就好。而map存在深拷贝和浅拷贝的问题。我定义的value是类而不是类指针,因此就是深拷贝,需要释放new出来的对象(原件)。而在最后调用clear()释放map的所有内存时,对象(副本)会去访问它的析构函数,进行内部释放,然后就只剩下raw memory,也就是没有被初始化的内存,它将被归还到alloc里面。如果我定义的是指针的话,clear()就只会释放指针而不会释放指针指向的内容,会产生内存泄漏,因此需要遍历map进行erase和delete来释放内存,比较麻烦。
4. 文件操作。文件操作时,我开始使用的是c语言的文件操作语法,由于string这种类类型的特殊性,输入输出的字符串均是乱码。然后我上网查询了一下,知道了要把string加上.c_str变为C语法的字符串才能正常输出。因此干脆就直接用C++的文件操作。在查询大量资料熟悉了C++的文件操作后,成功用流实现了文件的输入输出。其中也遇到了一个问题很有意思:判断文件结尾时如果直接用while(!fin.eof())会产生错误,查询资料后知道因为c++流很特殊,必须要在输入下一个的时候发现没有才会把fin的标志设置为false,fin.eof()才为true,而这样一来就会导致while循环多循环一次产生错误。知道原因也就很方便就能修改对应的代码了。
十二、对本实验过程及方法、手段的改进建议:
可以看见的是,没有图形化的界面在输入时需要加大量的判断而浪费时间空间,增加代码难度,因此对错误数据仅仅做了简单的判断处理。如果要实现更健壮的程序,需要加入图形化来处理比较方便。
附录:
程序:
#include<iostream>
#include<map>
#include<string>
#include<stdlib.h>
#include<fstream>
using namespace std;
class CStaff;
class CAdministrator;
class CTeacher;
class CTempStaff;
map<string,CTempStaff>tpmap;
map<string,CTeacher>tcmap;
map<string,CAdministrator>admap;
map<string,CTempStaff>::iterator tpit;
map<string,CTeacher>::iterator tcit;
map<string,CAdministrator>::iterator adit;
int CAA=100,CAB=100,CAS=100,CTS=100,TI1=10,TI2=20,TI3=30,TI4=40,MS=50,PHD=100;
//--------------------cstaff-----------------------
class CStaff{
protected:
string number;
string name;
char sex;
unsigned int serviceyears;
double salary;
public:
CStaff(string num,string na,char se,unsigned int sy,double sala)
{
number=num;
name=na;
sex=se;
serviceyears=sy;
salary=sala;
}
void SetSex(char se){
sex=se;
};
char GetSex(){
return sex;
}
void SetNo(string num){
number=num;
}
string GetNo(){
return number;
}
void SetName(string na){
name=na;
}
string GetName(){
return name;
}
bool SetServiceYears(unsigned int sy){
if (sy<=0)
return false;
serviceyears=sy;
return true;
}
unsigned int GetServiceYears(){
return serviceyears;
}
double GetBaseSalary(){
return salary;
}
virtual double GetSalary()=0;
};
//--------------------ctempstaff----------------------
class CTempStaff:public CStaff{
private:
double Ts;
public:
CTempStaff(string num,string na,char se,unsigned int sy,double sala,double t):CStaff(num,na,se,sy,sala){
Ts=t;
}
double GetSalary(){
return salary+Ts;
}
double GetTs(){
return Ts;
}
friend ostream&operator<<(ostream&out ,CTempStaff&obj);
};
ostream&operator << (ostream&out ,CTempStaff&obj){
out<<"姓名:"<<obj.GetName()<<endl;
if (obj.sex=='M')
out<<"性别:男"<<endl;
else
out<<"性别:女"<<endl;
out<<"职位:临时工"<<endl;
out<<"工号:"<<obj.GetNo()<<endl;
out<<"工龄:"<<obj.GetServiceYears()<<endl;
out<<"薪资:"<<obj.GetSalary()<<endl;
return out;
}
//--------------------cadmin-----------------------
class CAdministrator:public CStaff{
private:
string level;
public:
CAdministrator(string num,string na,char se,unsigned int sy,double sala,string lev):CStaff(num,na,se,sy,sala){
level=lev;
}
double GetSalary(){
if (!pare("一般"))
return salary+serviceyears*CAS;
else if (!pare("A"))
return salary+serviceyears*CAS+CAA;
else if (!pare("B"))
return salary+serviceyears*CAS+CAB;
}
string Getlevel(){
return level;
}
friend ostream&operator<<(ostream&out ,CAdministrator&obj);
};
ostream&operator << (ostream&out ,CAdministrator&obj){
out<<"姓名:"<<obj.GetName()<<endl;
if (obj.sex=='M')
out<<"性别:男"<<endl;
else
out<<"性别:女"<<endl;
if (!pare ("一般"))
out<<"职位:一般行政人员"<<endl;
else if (!pare ("A"))
out<<"职位:A级行政人员"<<endl;
else
out<<"职位:B级行政人员"<<endl;
out<<"工号:"<<obj.GetNo()<<endl;
out<<"工龄:"<<obj.GetServiceYears()<<endl;
out<<"薪资:"<<obj.GetSalary()<<endl;
return out;
}
//--------------------cteacher-----------------------
class CTeacher:public CStaff{
private:
string level;
long time,phd,master;
public:
CTeacher(string num,string na,char se,unsigned int sy,double sala,string lev,long ti,long ph,long ms):CStaff(num,na,se,sy,sala){
level=lev;
time=ti;
phd=ph;
master=ms;
}
double GetSalary(){
if (!pare("讲师"))
return salary+serviceyears*CTS+time*TI1;
else if (!pare("副教授"))
return salary+serviceyears*CTS+time*TI2+master*MS;
else if (!pare("教授"))
return salary+serviceyears*CTS+time*TI3+master*MS;
else if (!pare("博导"))
return salary+serviceyears*CTS+time*TI4+master*MS+phd*PHD;
}
string Getlevel(){
return level;
}
long Gettime(){
return time;
}
long Getphd(){
return phd;
}
long Getmaster(){
return master;
}
friend ostream&operator<<(ostream&out ,CTeacher&obj);
};
ostream&operator << (ostream&out ,CTeacher&obj){
out<<"姓名:"<<obj.GetName()<<endl;
if (obj.sex=='M')
out<<"性别:男"<<endl;
else
out<<"性别:女"<<endl;
if (!pare ("讲师"))
out<<"职位:讲师"<<endl;
else if (!pare ("副教授"))
out<<"职位:副教授"<<endl;
else if (!pare ("教授"))
out<<"职位:教授"<<endl;
else
out<<"职位:博导"<<endl;
out<<"工号:"<<obj.GetNo()<<endl;
out<<"工龄:"<<obj.GetServiceYears()<<endl;
out<<"薪资:"<<obj.GetSalary()<<endl;
return out;
}
//--------------------删除函数----------------------
bool deletestaff()
{
string tnum;
char yn;
cin>>tnum;
tpit=tpmap.find (tnum);
if (tpit!=tpmap.end())
{
cout<<endl<<"信息如下:"<<endl<<tpit->second<<endl<<"确认删除?Y/N"<<endl;
cin>>yn;
if (yn=='Y')
{
tpmap.erase(tpit);
return true;
}
return false;
}
tcit=tcmap.find(tnum);
if (tcit!=tcmap.end())
{
cout<<endl<<"信息如下:"<<endl<<tcit->second<<endl<<"确认删除?Y/N"<<endl;
cin>>yn;
if (yn=='Y')
{
tcmap.erase(tcit);
return true;
}
return false;
}
adit=admap.find(tnum);
if (adit!=admap.end())
{
cout<<endl<<"信息如下:"<<endl<<adit->second<<endl<<"确认删除?Y/N"<<endl;
cin>>yn;
if (yn=='Y')
{
admap.erase(adit);
return true;
}
return false;
}
return false;
}
//--------------------访问函数----------------------
bool visitstaff()
{
string tnum;
cin>>tnum;
tpit=tpmap.find (tnum);
if (tpit!=tpmap.end())
{
cout<<endl<<"信息如下:"<<endl<<tpit->second<<endl;
return true;
}
tcit=tcmap.find(tnum);
if (tcit!=tcmap.end())
{
cout<<endl<<"信息如下:"<<endl<<tcit->second<<endl;
return true;
}
adit=admap.find(tnum);
if (adit!=admap.end())
{
cout<<endl<<"信息如下:"<<endl<<adit->second<<endl;
return true;
}
return false;
}
//--------------------新增函数----------------------
bool newstaff()
{
int op1;
string number;
string name;
char sex;
unsigned int serviceyears;
double salary;
string level;
short level2;
long time,master=0,phd=0;
cout<<"姓名:";
cin>>name;
cout<<"性别(F/M):";
cin>>sex;
cout<<"工号:";
cin>>number;
tpit=tpmap.find (number);
tcit=tcmap.find(number);
adit=admap.find(number);
if (tpit!=tpmap.end()||tcit!=tcmap.end()||adit!=admap.end())
{cout<<"此工号已经被占用!"<<endl;
return false;
}
cout<<"工龄:";
cin>>serviceyears;
cout<<"基础工资:";
cin>>salary;
cout<<"职位:1-临时工 2-行政人员 3-教师"<<endl;
cin>>op1;
switch (op1)
{
case 1:{double Ts;
cout<<"临时工固定工资:";
cin>>Ts;
CTempStaff *c1=new CTempStaff(number,name,sex,serviceyears,salary,Ts);
tpmap.insert(pair<string,CTempStaff>(c1->GetNo(),*c1));
delete c1;
return true;}
case 2:{cout<<"行政级别(一般/A/B):";
cin>>level;
CAdministrator *c2=new CAdministrator(number,name,sex,serviceyears,salary,level);
admap.insert(pair<string,CAdministrator>(c2->GetNo(),*c2));
delete c2;
return true;}
case 3:cout<<"教师职称(1-讲师 2-教授 3-副教授 4-博导):"<<endl;
cin>>level2;
switch (level2){
case 1:{cout<<"输入授课时间:";
cin>>time;
CTeacher *c3=new CTeacher(number,name,sex,serviceyears,salary,"讲师",time,phd,master);
tcmap.insert(pair<string,CTeacher>(c3->GetNo(),*c3));
delete c3;
return true;}
case 2:{cout<<"输入授课时间、所带硕士生数,空格间隔,回车结束:"<<endl;
cin>>time>>master;
CTeacher *c4=new CTeacher(number,name,sex,serviceyears,salary,"教授",time,phd,master);
tcmap.insert(pair<string,CTeacher>(c4->GetNo(),*c4));
delete c4;
return true;}
case 3:{cout<<"输入授课时间、所带硕士生数,空格间隔,回车结束:"<<endl;
cin>>time>>master;
CTeacher *c5=new CTeacher(number,name,sex,serviceyears,salary,"副教授",time,phd,master);
tcmap.insert(pair<string,CTeacher>(c5->GetNo(),*c5));
delete c5;
return true;}
case 4:{cout<<"输入授课时间、所带硕士生数,所带博士生数,空格间隔,回车结束:"<<endl;
cin>>time>>master>>phd;
CTeacher *c6=new CTeacher(number,name,sex,serviceyears,salary,"博导",time,phd,master);
tcmap.insert(pair<string,CTeacher>(c6->GetNo(),*c6));
delete c6;
return true;}
}
}
return false;
}
//--------------------编辑函数----------------------
bool editstaff()
{
string tnum;
char yn,sex;
int op,serviceyears,op1;
string name,number;
cin>>tnum;
tpit=tpmap.find (tnum);
tcit=tcmap.find(tnum);
adit=admap.find(tnum);
if (tpit!=tpmap.end())
{
op1=1;
cout<<endl<<"信息如下:"<<endl<<tpit->second<<endl;
}
else if (tcit!=tcmap.end())
{
op1=2;
cout<<endl<<"信息如下:"<<endl<<tcit->second<<endl;
}
else if (adit!=admap.end())
{
op1=3;
cout<<endl<<"信息如下:"<<endl<<adit->second<<endl;
}
else
return false;
if (tpit!=tpmap.end()||tcit!=tcmap.end()||adit!=admap.end())
cout<<"输入要修改的项目:1-姓名 2-性别 3-工龄"<<endl
展开阅读全文