浙江大学城市学院实验报告
课程名称 Java高级程序设计
实验项目名称 多线程应用基础实验 学生姓名 专业班级 学号
一、实验目的
1. 掌握多线程的基本概念
2. 掌握两种线程的建立方法
3. 掌握线程的协同控制方法
4. 掌握多线程程序设计
二、实验内容
2. 控制执行长时间任务的线程。
3. 编写一个生产者和消费者模型的程序。
1)给出不同线程的协作说明;
2)实现生产者线程;
3)实现消费者线程;
4. 设计一个多线程程序,模拟银行业务办理。
1) 给出银行模拟场景说明;
2) 设计出所有需要的线程,并说明其作用;
3) 实现各个线程功能;
4) 打印实验结果,计算业务办理平均时间
1. 用两种方式实现多线程,即编写Thread子类或实现Runnable接口
三. 实验结果与分析(可将程序运行结果截屏,也可简单分析运行结果)
四. 讨论、心得(可写遇到的问题及解决方法,或者对技术的理解等)
第二篇:班级学号姓名实验报告
“C++及其编程思想”实验报告
专 业:
姓 名:
学 号:
20##年8月28日
实验一 熟悉Visual C++集成开发环境
一、实验目的及要求
1.掌握启动和退出VC6的方法。
2.熟悉VC6开发环境,初步掌握菜单栏、工具栏、项目工作区、文件编辑区、输出区和状态栏等的使用。
3.初步掌握简单程序的上机操作基本步骤,学会建立工程、建立单文件和多文件程序,正确进行编译、链接和运行程序,查找并修改简单的语法错误。
4.通过编程熟悉C++语言源程序的编程风格,掌握用cin>>和cout<<进行输入和输出的处理方式,正确进行源代码的单行注释。
二、实验内容
在D盘上建立以自己学号姓名命名的文件夹(例如,407020518张三丰,以后实验的源程序文件存于此文件夹中),编写C++风格的源程序
在自己的文件夹下建立一个名为exp1的工程,然后用建立新文件向工程添加的方式添加3个文件,实现求阶乘。文件名分别为fac.h、fac.cpp和main.cpp,在头文件fac.h中给出求阶乘的函数的原型声明;在fac.cpp文件中给出求阶乘的函数的完整定义;在main.cpp中定义main函数,定义相关的变量,输入变量的值并进行一定的数据合理性判断,在数据非法时给出一定的提示信息并退出程序的运行,对于正确的数据,则调用求阶乘的函数,求出阶乘并输出。在每个函数开头加注释说明函数的功能、入口参数、返回值情况,对函数的关键语句用单行方式注释。
三、程序
四、实验结果
五.总结
实验二 用C++实现面向过程的程序设计
一、实验目的及要求
1.掌握用C++语言实现面向过程的程序设计方法。
2.正确理解引用作为形式参数和函数返回值的意义和用法,并与值形式参数、指针参数做比较。
二、实验内容
在自己的文件夹下建立一个名为exp2的工程,在该工程中添加新文件exp2.cpp,文件内容如下:
#include <iostream>
using namespace std;
void swap(int x,int y);
void main()
{
int x=10,y=20;
cout<<”Before swap, x=”<<x<<”y=”<<y<<endl;
swap(x,y);
cout<<”After swap, x=”<<x<<”y=”<<y<<endl;
}
void swap(int x,int y)
{
int t=x;
x=y;
y=t;
}
(1)编辑、编译、连接并运行程序,观察运行结果。
(2)根据调试器的使用方法,对以上程序的运行进行单步跟踪。注意:在运行到语句swap(x,y);时使用F11键(Step Into 进入到函数体内执行)跟踪,观察swap函数执行的每一步各变量的变化情况;其余语句处使用F10键(Step Over 单步执行)跟踪,记录实际参数x、y的内存地址&x、&y,以及x、y在调用swap函数前后的变化情况;记录形式参数x、y的内存地址&x、&y,注意与实际参数的地址是否相等,以及形式参数x、y在调用swap函数过程中的变化情况,解释实际参数未能发生交换的原因。
(3)将上述程序代码中函数原形及函数定义首部的void swap(int x,int y)修改为void swap(int &x,int &y),再次运行程序,观察运行结果。
实验指导:
(1)在跟踪调试时注意正确使用两种不同的单步跟踪方法:按下F10键实现Step Over跟踪,而按下F11键实现Step Into跟踪。此程序中,只有在调用swap函数这一行时需要按下F11键,其余位置都按F10即可。
(2)对于需要查看的信息,如果未在auto窗口中出现,可以在watch窗口中输入相应的内容,便于进行观察。
三、程序
四、实验结果
五、总结
实验三 类与对象的实践
一、实验目的及要求
1.掌握类和对象的概念、定义和使用方法。
2.掌握不同特性对象成员的访问方法,以及this指针的概念和使用方法。
3.掌握构造函数和析构函数的使用方法。
4.掌握复合类的定义。
二、实验内容
在自己的文件夹下建立一个名为exp3的工程,在该工程中做如下操作:
1.定义一个以hours, minutes和seconds作为数据成员的CTime类。设计如下成员函数:
(1)无参构造函数、带三个参数的构造函数、析构函数
(2)修改成员数据的成员函数void Set(int hours,int minutes,int seconds);
(3)修改hours的成员函数void SetHours(int hours);
(4)修改minutes的成员函数void SetMinutes(int minutes);
(5)修改seconds的成员函数void SetSeconds(int seconds);
(6)获取hours的成员函数int GetHours();
(7)获取minutes的成员函数int GetMinutes();
(8)获取seconds的成员函数int GetSeconds();
(9)设计一个显示时间的函数。
2.定义了一个以year, month,day,hours, minutes和seconds作为数据成员的CDateTime日期时间类。但是hours, minutes和seconds数据成员可以用Time类定义。也就是CDateTime的数据成员可以如下定义:
class CDateTime
{
private:
int year;
int month;
int day;
CTime time;
};
成员函数要求有如下:
(1)无参构造函数初始化为(20##-10-15日0:0:0)、带三个参数的构造函数(注意使用复合类的构造函数的定义方式)、析构函数。
(2)修改成员数据的成员函数void Set(int years,int months,int days,int hours,int minutes,int seconds);
(3)修改year的成员函数void SetYear(int yeasr);
(4)获取year的成员函数int GetYear();
(5)修改month的成员函数void SetMonth(int months);
(6)获取month的成员函数int GetMonth();
(7)修改day的成员函数void SetDay(int days);
(8)获取day的成员函数int GetDay();
(9)显示日期时间的函数void ShowDateTime(void);
(10)显示日期的函数void ShowDate(void);
(11)显示时间的函数void ShowTime(void);
(12)设计一个CDateTime对象加上一个整数(秒数),并把相加的结果赋值给该对象。注意相加时seconds、 minutes、hours、day、month、year的变化。(附加题,学有余力的同学完成)
设计两个CDateTime对象相减运算的成员函数。函数输出结果为整数(秒数)。(附加题,学有余力的同学完成)
要求:
(1)把CTime类的声明放在time.h文件中。
(2)把CTime成员函数的定义放在time.cpp文件中。
(3)把CDateTime类的声明放在datetime.h文件中
(4)把CDateTime成员函数的定义放在datetime.cpp文件中。
(5)把main函数的部分放在test3.cpp中。
(6)主函数中正确定义两个类的对象,调用各自的成员函数实现相应功能。
三、程序
四、实验结果
五、总结
实验四 继承与派生
一、实验目的及要求
1.掌握单继承和多重继承下派生类的定义方法,理解基类成员在不同的继承方式下不同的访问属性。
2.正确定义派生类的构造函数与析构函数,理解定义一个派生类对象时各个构造函数、析构函数被调用的顺序。
3.正确定义虚基类,消除在多层次继承方式下顶层基类中成员访问的二义性问题,关注此时各构造函数、析构函数的调用顺序。
4.通过基类与派生类的定义,及基类对象、指针、引用与派生类的对象、地址间相互赋值的方法,正确理解赋值兼容的4种情况,通过程序理解其不可逆性。
二、实验内容
在自己的文件夹下建立一个名为exp4的工程,在该工程中做如下操作:
定义一个车基类,派生出自行车类和汽车类,又以自行车类和汽车类为基类共同派生出摩托车类,每个类都要定义带有参数的构造函数。对自行车类继承基类的方式分别用private、protected、public,观察基类成员在派生类中的访问属性;观察自行车类、汽车类和摩托车类对象定义时构造、析构函数的调用顺序。最后将车基类定义为虚基类再观察程序运行结果,具体完成以下要求。
(1)定义基类Vehicle,具有两个保护成员变量:MaxSpeed、Weight,有3个公有的成员函数:Run()、Stop()、Show(),以及带参数构造函数、析构函数;再定义一个从Vehicle公有继承的Bicycle类,增加Height保护属性的成员变量,定义Bicycle类的构造函数、析构函数,改造Show函数,用于输出本类中的完整信息。main()函数中定义Bicycle类对象,观察构造函数和析构函数的执行顺序,以及各成员函数的调用。请用单步跟踪的方法观察程序运行的每一步究竟调用的是哪一个函数,析构函数的跟踪方法可以采用在析构函数中设置断点的方法。
(2)在上一步基础上,将继承方式分别修改为protected和private,再重新编译,观察这时的报错信息并能解释。修改程序使程序正确运行。
(3)将Bicycle类的继承方式恢复为public,代码回到(1)的状态,再在Bicycle类下面增加一个第二层汽车类Car的定义,Car也是公有继承基类Vehicle,其中增加了一个保护成员变量SeatNum,表示汽车有几个座位,其定义方式与类Bicycle类似。主函数中定义该对象,观察运行结果。
(4)在上一步的基础上,再定义一个第三层类MotorCycle,该类以公有继承方式继承了第二层的Bicycle和Car类。定义其构造函数,要调用两个直接基类的构造函数,再改造函数Show(),输出所有四个成员变量的信息。主函数中只定义类MotorCycle的对象并调用相应的函数,代码请参考实验指导的(4)。程序进行编译,会产生4个错误、8个警告,因为存在二义性问题,请采用在同名成员前增加“基类名::”以消除二义性直到程序正确,观察运行结果。
(5)再将代码恢复至上一步未修改前,即存在4个错误、8个警告的状态,再作一定的修改,将Vehicle声明为虚基类以消除二义性,同时修改第三层的构造函数,其余代码不变,具体请参考实验指导的(5),观察运行结果,理解此时构造函数、析构函数的调用顺序及用虚基类消除二义性的原理。
三、 实验指导
(1)基类Vehicle和派生类Bicycle的定义如下,主函数定义派生类对象并调用相应函数,划线处需要自己填写。
#include<iostream>
using namespace std;
class Vehicle //定义基类
{protected:
int MaxSpeed; //最大速度
int Weight; //重量
public:
Vehicle(){};
Vehicle(int m,int w) //初始化成员变量的值
{
cout<<”Constructing Vehicle…\n”;
}
~Vehicle( )
{
cout<<”Destructing Vehicle…\n”;
}
void Run()
{
cout<<”The vehicle is running! \n”;
}
void Stop()
{
cout<<”Please stop running! \n”;
}
void Show()
{
cout<<”It\’s maxspeed is:”<<MaxSpeed<<endl;
cout<<”It\’s weight is:”<<Weight<<endl;
}
};
class Bicycle:public Vehicle //定义派生类,公有继承
{
protected:
int Height; //高度,单位:厘米
public:
Bicycle():Vehicle() {}
Bicycle(int m,int w,int h): //调用基类构造函数
{
//为本类中新增成员提供初值
cout<<”Constructing Bicycle…\n”;
}
~Bicycle()
{
cout<<”Destructing Bicycle…\n”;
}
void Show() //改造基类的Show函数
{
//调用基类Show输出MaxSpeed和Weight值
//输出本类高度
}
};
int main()
{
Bicycle //定义派生类对象
b.Run(); //观察构造、析构函数调用顺序
b.Stop();
b.Show();
return 0;
}
(2)将继承方式改为private或protected时,有多种修改错误的方法,这里要求继承方式不动,因此最简单的方式就是访问声明将基类原有的公有成员继续保持其公有属性,在派生类的public:关键字下增加访问声明。
(3)将Bicycle类的继承方式恢复为public。在Bicycle类下面增加Car类的定义,参考以下代码,划线部分自己完成。
class Car:public Vehicle //定义派生类Car,公有继承
{
protected:
int SeatNum; //座位数
public:
Car() :Vehicle() {}
Car(int m,int n,int s): //调用基类构造函数
{
//为本类中新增成员提供初值
cout<<”Constructing Car…\n”;
}
~Car()
{
cout<<”Destructing Car…\n”;
}
void Show() //改造基类的Show函数
{ //调用基类Show输出MaxSpeed和Weight值
//输出本类座位数
}
};
再在主函数中增加Car类对象的定义并调用相应函数,主函数代码如下。
int main()
{Bicycle //定义自行车类对象
b.Run();
b.Stop();
b.Show();
Car //定义汽车类对象
c.Run();
c.Stop();
c.Show();
return 0;
}
(4)增加的第3层类MotorCycle及修改以后的main()函数。
class MotorCycle:public Bicycle,public car//第3层类,从第2层两个类公有继承
{public:
MotorCycle(int m,int w,int h,int s): //调用两基类构造函数
{
cout<<”Constructing MotorCycle…\n”;
}
~MotorCycle()
{
cout<<”Destructing MotorCycle…\n”;
}
void Show() //输出4个成员变量的信息,需消除二义性
{
cout<<”It\’s maxspeed is:”<<MaxSpeed<<endl; //错误
cout<<”It\’s weight is:”<<Weight<<endl; //错误
cout<<”It\’s height is:”<<Height<<endl;
cout<<”It\’s seatnum is:”<<SeatNum<<endl;
}
};
int main()
{
MotorCycle //定义摩托车类对象
mc.Run(); //错误
mc.Stop(); //错误
mc.Show();
return 0;
}
(5)将Vehicle声明为虚基类以消除二义性,具体要在上面的基础上修改3个地方。
将class Bicycle:public Vehicle 修改为 class Bicycle:virtual public Vehicle
将class Car:public Vehicle修改为class Car:virtual public Vehicle
在第3层类的构造函数MotorCycle(int m,int w,int h,int s): 的初始化列表中增加对虚基类构造函数的调用。观察运行结果,理解此时构造函数、析构函数的调用顺序及用虚基类消除二义性的原理。
三、程序
四、实验结果
五、总结
实验五 重载
一、实验目的及要求
1.掌握运算符重载的定义及实现。
2.掌握具有运算符重载的应用。
二、实验内容
在自己的文件夹下建立一个名为exp6的工程,在该工程中做如下操作:
定义一个复数类CComplex,通过重载运算符: *,/,直接实现二个复数之间的乘除运算。编写一个完整的程序,测试重载运算符的正确性。要求乘法“*”用成员函数实现重载,除法“/”用友元函数实现重载。
两复数相乘的计算公式为:
(a+b i)*(c+d i)=(ac–bd )+(ad+bc) i
两复数相除的计算公式为:
(a+bi)/(c+di)=(ac+bd)/(c*c+d*d)+(bc-ad)/(c*c+d*d) i
成员函数有:
(1)无参构造函数初始化为原点并输出如下提示” CComplex无参构造函数 ”
(2)带两个参数的构造函数并输出如下提示” CComplex带两个参数的构造函数”
(3)输出函数void print ()
(4)乘法*成员函数重载
(5)除法/友元函数重载
要求:
(1)把点类CComplex的声明放在complex.h文件中
(2)把点类CComplex成员函数的定义放在complex.cpp文件中
(3) 把main函数的部分放在exp6.cpp中并对如上的运算符重载函数分别进行测试。
三、程序
四、实验结果
五、总结
实验六 虚函数和多态
一、实验目的及要求
1.进一步熟悉类的设计、运用继承与派生机制设计派生类,合理设置数据成员和成员函数。
2.掌握通过继承、虚函数、基类的指针或引用实现动态多态性的方法。
3.理解并掌握具有纯虚函数的抽象类的作用,在各派生类中重新定义各纯虚函数的方法,以及此时实现的动态多态性。
二、实验内容
在自己的文件夹下建立一个名为exp5的工程,在该工程中做如下操作:
定义一个抽象类容器类,其中定义了若干纯虚函数,实现求表面积、体积、输出等功能。由此抽象类派生出正方体、球体和圆柱体等多个派生类,根据需要定义自己的成员变量,在各个派生类中重新定义各纯虚函数,实现各自类中相应功能,各个类成员的初始化均由本类构造函数实现。
(1)在主函数中,定义容器类的指针和各个派生类的对象,使指针指向不同对象处调用相同的函数能执行不同的函数代码,从而实现动态多态性。
(2)定义一个顶层函数void TopPrint(Container &r);使得主函数中调用该函数时,根据实在参数所有的类自动调用对应类的输出函数。
(3)主函数中定义一个Container类对象,观察编译时的错误信息,从而得出什么结论?
三、 实验指导
(1)基类Container的定义形式如下。
class Container
{protected:
double radius;
public:
Container(double r)
{
… //完成构造函数代码
}
virtual double area()=0; //求表面积
virtual double volume()=0; //求体积
virtual void print()=0; //输出相关信息
};
(2)各个派生类的定义形式如下。
class Cube: //正方体类,从Container类公有继承
{
… //构造函数
… //重新定义基类的3个纯虚函数
};
class Sphere: //球类,从Container类公有继承
{
… //构造函数
… //重新定义基类的3个纯虚函数
};
class Cylinder: //圆柱体类,从Container类公有继承
{
… //需要增加的成员变量
… //构造函数
… //重新定义基类的3个纯虚函数
};
(3)通过运行结果,理解动态多态性主函数形式如下。
void main()
{
Container *p; //定义抽象类指针
Cube 正方体对象; //根据构造函数提供实参
Sphere 球体对象; //根据构造函数提供实参
Cylinder 圆柱体对象; //根据构造函数提供实参
p=&正方体对象;
cout<<p->area()<<endl;
cout<<p->volume()<<endl;
p->print();
p=&球体对象;
cout<<p->area()<<endl;
cout<<p->volume()<<endl;
p->print();
p=&圆柱体对象;
cout<<p->area()<<endl;
cout<<p->volume()<<endl;
p->print();
}
(4)在主函数中定义Container类的对象,记下编译器的报错信息。
三、程序
四、实验结果
五、总结
实验七 流类库与输入输出
一、实验目的
1.掌握流的概念。
2.掌握文件流的打开、读/写与关闭的方法。
3.理解文本文件流与二进制文件流在操作上的区别
二、实验内容与要求
在自己的文件夹下建立一个名为exp9的工程,在该工程中做如下操作:
编程题:
1.建立一个文本文件“data.txt”(内容由读者选定),然后显示该文件,并统计该文件的行数。
2.建立某单位职工通讯录的二进制文件。
(1)文件中的每个记录包括职工编号、姓名、电话号码、邮政编码和地址。
(2)文件中的内容自定。
(3)从键盘上输入职工的编号,在文件中查找该职工的资料,查找成功时,显示职工的姓名、电话号码、邮政编码和地址。
(4)在文件的末尾添加新纪录。
三、程序
四、实验结果
五、总结
实验八 模板
一、实验目的
1.掌握函数模板定义和使用方法。
2. 掌握类模板定义和使用方法。
二、实验内容与要求
在自己的文件夹下建立一个名为exp7的工程,在该工程中做如下操作:
下列2个题目均要完成。
1.阅读下列程序,写出程序的功能,然后使用模板函数改写该程序并上机验证。
#include<iostream.h>
void exchange(int &x,int &y,int &z)
{
int temp1=y,temp2=z;
y=x; z=temp1; x=temp2;
}
void exchange(float &x,float &y,float &z)
{
float temp1=y,temp2=z;
y=x; z=temp1; x=temp2;
}
void exchange(double &x,double &y,double &z)
{
double temp1=y,temp2=z;
y=x; z=temp1; x=temp2;
}
void main()
{
int i,j,k;
cout<<"i,j,k=";
cin>>i>>j>>k;
exchange(i,j,k);
cout<<i<<'\t'<<j<<'\t'<<k<<endl;
float a,b,c;
cout<<"a,b,c=";
cin>>a>>b>>c;
exchange(a,b,c);
cout<<a<<'\t'<<b<<'\t'<<c<<endl;
double u,v,w;
cout<<"u,v,w=";
cin>>u>>v>>w;
exchange(u,v,w);
cout<<u<<'\t'<<v<<'\t'<<w<<endl;
}
2.下面是一个数组CArray类的定义,将其定义成一个类模板,使其能够表示不同类型的数组,并在主函数中测试其实例化的模板类。
#include<iostream.h>
class CArray
{
private:
int *p_arr;
int size;
public:
CArray();
CArray(int *p_a,int s);
~ CArray();
void print() const; //打印数组元素的成员函数
};
CArray::CArray()
{
p_arr=0;
size=0;
}
CArray::CArray(int *p_a,int s)
{
if(s>0)
{
size=s;
p_arr=new int[size];
for(int i=0;i<size;i++)
p_arr[i]=p_a[i];
}
else
{
p_arr=0;
size=0;
}
}
CArray::~CArray()
{
if(p_arr)
delete []p_arr;
}
三、程序
四、实验结果
五、总结
实验九 异常处理
一、实验目的
1.掌握异常处理的概念,理解异常处理的意义。
2. 掌握异常处理的实现机制和方法。
二、实验内容与要求
在自己的文件夹下建立一个名为exp8的工程,在该工程中做如下操作:
编程题:
从键盘上输入x和y的值,计算y=ln(2x-y)的值,要求用异常处理“负数求对数”的情况
三、程序
四、实验结果
五、总结