1、 电子科技大学计算机学院 标 准 实 验 报 告 (实验)课程名称:C++程序设计实验 电子科技大学教务处制表 电 子 科 技 大 学 实 验 报 告 学生姓名: 学 号: 指导教师:丘志杰 实验地点:主楼A2-412 实验时间:2012.11.23 一、实验室名称:电子科技大学计算机实验教学示范中心 二、实验项目名称:C++程序设计实验 三、实验学时:24学时 四、实验原理: 了解数据封装的作
2、用和实现方式,使用C++语言的抽象数据类型实现数据封装。了解继承的实现方式,使用C++语言的基类和派生类实现继承功能。了解运算符重载的机制,学会进行运算符重载。了解继承和多态的作用和实现方式,掌握动态联编方法,使用C++语言的抽象类和派生类实现继承性。 五、实验目的: 1、 掌握C++编程规范; 2、 掌握C++的封装、继承、运算符重载以及多态程序的基本编写方法; 3、 熟悉在visual Studio 2010(及以上版本)环境下的C++软件开发和调试过程。 六、实验内容: C++编辑和编译系统采用Visual Studio 2010,设计1个综合运用数据封装、继承、运算符重载、
3、多态等机制的C++编程语言的应用实验“学校教职工工资管理程序”:对学校教职工进行关系划分;着重应用数据封装、继承等机制对各类人员进行类封装并体现继承和派生关系;着重应用虚函数机制,实现计算职工工资的功能;重载“<<”运算符,能够对对象进行信息输出。 七、实验器材(设备、元器件): 1.硬件平台: 【电脑型号 戴尔 System Inspiron N4110 笔记本电脑】 【处理器 英特尔 第二代酷睿 i3-2350M @ 2.30GHz 双核】 速度 2.30 GHz (100 MHz x 23.0) 处理器数量 核心数: 2 / 线程数: 4 核心代号 Sandy Bridg
4、e 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 芯
5、片组)】 板载设备 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 制造日期
6、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 制造商 戴尔
7、 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.
8、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++ 2
9、012 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 St
10、udio 2010环境下,对各类教职工进行数据封装,并应用继承和派生机制实现类的继承功能; (3) 应用虚函数机制,设计计算职工工资的功能,并在Visual Studio 2010环境下实现该功能; (4) 应用运算符重载机制,在Visual Studio 2010环境下实现对“<<”运算符的重载,能够对对象进行信息输出。 3. 编译和调试 (1) 编译相应的C++程序,若不通过,则检查出错原因; (2) 在编译通过的情况下,调试程序,看运行结果是否与预期一致。通过单步或函数级跟进调试程序; 4. 美化和优化程序编写规范和结果显示形式 5. 截取实验结果图和撰写实验报告 九、实
11、验数据及结果分析: 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:临时工,在员工基础上增加临时工工资; CAdministrat
12、or:行政人员,在员工基础上增加“一般、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 dsa
13、f 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
14、项选择界面。输入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所示。 【第六步】修改测试。程序
15、自动回到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 王三 2
16、1 F 一般 20 7000 0 0 0 0 可以看见新增了“刘ABC“员工的信息,删除了”meng”员工的信息,修改了”21“工号员工的姓名,程序测试成功。如附录截图5所示。 十、实验结论: 程序实现了一个程序实现学校教职工的工资管理,根据相应计算方式设计了类,重载了<<运算符,并且实现了教职工信息的增加、修改、删除、查询、以及持久化到磁盘中等基本要求。同时,程序还增加了判断,保证了工号的唯一性,优化了数据结构,提升了程序的稳定性、优化了时空复杂度。程序提供了比较好的人机交互界面,用户能根据提示管理整个系统。 十一、总结及心得体会: 这次实验我学习了很多东西: 1. 首先遇到的问
17、题是类的实现。由于不熟练,查询了大量的资料才得以编程,建立了类的继承关系,理清了工资计算方式,实现了封装等操作。 2. 重载运算符。由于C++书上没有<<重载的相关代码,而<<重载的步骤和普通+-重载不同,极为复杂,需要用到友元类,经过上网查询、请教老师同学、比较完善地重载了<<运算符。 3. Map相关。在考虑采用数据结构存储中,首先想到了数组和普通链表,但是由于数组时间复杂度高,空间无法扩展,普通链表操作难度大,时间复杂度也很高。我考虑了采用STL中的map,map能产生键值对应的关系,而工号正好是满足要求的key。同时,map采用的是一种非常高效的非严格意义上的平衡检索二叉树:红黑树
18、red-black tree),基本上所有操作都是O(log2n),而且能够自动扩容,提供了大量接口函数,极为方便稳定快捷。因此我采用了map来存储数据。STL操作中遇到了一个有意思的问题:就是释放内存。由于类里面没有数组等数据结构,因此用默认析构函数就好。而map存在深拷贝和浅拷贝的问题。我定义的value是类而不是类指针,因此就是深拷贝,需要释放new出来的对象(原件)。而在最后调用clear()释放map的所有内存时,对象(副本)会去访问它的析构函数,进行内部释放,然后就只剩下raw memory,也就是没有被初始化的内存,它将被归还到alloc里面。如果我定义的是指针的话,clear
19、)就只会释放指针而不会释放指针指向的内容,会产生内存泄漏,因此需要遍历map进行erase和delete来释放内存,比较麻烦。 4. 文件操作。文件操作时,我开始使用的是c语言的文件操作语法,由于string这种类类型的特殊性,输入输出的字符串均是乱码。然后我上网查询了一下,知道了要把string加上.c_str变为C语法的字符串才能正常输出。因此干脆就直接用C++的文件操作。在查询大量资料熟悉了C++的文件操作后,成功用流实现了文件的输入输出。其中也遇到了一个问题很有意思:判断文件结尾时如果直接用while(!fin.eof())会产生错误,查询资料后知道因为c++流很特殊,必须要在输入
20、下一个的时候发现没有才会把fin的标志设置为false,fin.eof()才为true,而这样一来就会导致while循环多循环一次产生错误。知道原因也就很方便就能修改对应的代码了。
十二、对本实验过程及方法、手段的改进建议:
可以看见的是,没有图形化的界面在输入时需要加大量的判断而浪费时间空间,增加代码难度,因此对错误数据仅仅做了简单的判断处理。如果要实现更健壮的程序,需要加入图形化来处理比较方便。
附录:
程序:
#include
21、 22、istrator>::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(stri 23、ng 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;
}
24、
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 25、
}
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 GetSalar 26、y(){
return salary+Ts;
}
double GetTs(){
return Ts;
}
friend ostream&operator<<(ostream&out ,CTempStaff&obj);
};
ostream&operator << (ostream&out ,CTempStaff&obj){
out<<"姓名:"< 27、临时工"< 28、ing 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*CA 29、S+CAB;
}
string Getlevel(){
return level;
}
friend ostream&operator<<(ostream&out ,CAdministrator&obj);
};
ostream&operator << (ostream&out ,CAdministrator&obj){
out<<"姓名:"< 30、"))
out<<"职位:一般行政人员"< 31、
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(){ 32、
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+mast 33、er*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<<"姓名: 34、"< 35、
out<<"工龄:"< 36、<<"信息如下:"< 37、d< 38、ndl;
cin>>yn;
if (yn=='Y')
{
admap.erase(adit);
return true;
}
return false;
}
return false;
}
//--------------------访问函数----------------------
bool visitstaff()
{
string tnum;
cin>>tnum;
tpit=tpmap.f 39、ind (tnum);
if (tpit!=tpmap.end())
{
cout< 40、p.find(tnum);
if (adit!=admap.end())
{
cout< 41、t 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!=t 42、cmap.end()||adit!=admap.end())
{cout<<"此工号已经被占用!"< 43、ff *c1=new CTempStaff(number,name,sex,serviceyears,salary,Ts);
tpmap.insert(pair 44、l);
admap.insert(pair 45、x,serviceyears,salary,"讲师",time,phd,master);
tcmap.insert(pair 46、ime,phd,master);
tcmap.insert(pair 47、ap.insert(pair 48、tring,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);
49、
tcit=tcmap.find(tnum);
adit=admap.find(tnum);
if (tpit!=tpmap.end())
{
op1=1;
cout<






