面向对象程序设计实验任务和指导1.docx
《面向对象程序设计实验任务和指导1.docx》由会员分享,可在线阅读,更多相关《面向对象程序设计实验任务和指导1.docx(17页珍藏版)》请在冰豆网上搜索。
![面向对象程序设计实验任务和指导1.docx](https://file1.bdocx.com/fileroot1/2023-2/25/c5cb1127-26d1-4076-b2b7-4d0a12914ae6/c5cb1127-26d1-4076-b2b7-4d0a12914ae61.gif)
面向对象程序设计实验任务和指导1
文档发表日期:
2012-04-14
最近修改日期:
2014-09-01
《面向对象程序设计》实验任务及指导
目录
一、实验1:
熟悉实验环境
二、实验2:
数据抽象
三、实验3:
继承与多态性
三、实验4:
重载和I/O流及面向对象程序设计
一、实验1:
熟悉实验环境
【实验目的】
●熟悉VisualC++6.0开发环境。
●掌握多文件结构程序项目的建立过程。
●初步掌握面向对象程序的多文件结构项目的开发运行步骤。
【实验内容】
1、学习多文件结构程序项目的建立过程,观看、体会演示。
2、下面的程序在编译时会出错,请修改程序,使之能正确运行。
#include
//#include"iostream"或#include"iostream.h"
//#include"文件名":
使用<>表示在包含文件目录中去查找(包含目录是由用户在设置环境时设置的),而不在源文件目录去查找;使用双引号””则表示首先在当前的源文件目录中查找,若未找到才到包含目录中去查找。
一般使用双引号””..h是引用C语言库.
usingnamespacestd;
classMyClass
{
public:
MyClass(){x=0;y=0;}
MyClass(inta=0,b=0);
Print();
private:
intx,y;
};
MyClass:
:
MyClass(inta=0,intb=0)
{
x=a;
y=b;
}
voidMyClass:
:
Print()
{
cout<<"x="<cout<<"y="<}
intmain()
{
MyClassobj1,obj2(5,8);
obj1.x=1;
obj1.y=3;
obj1.Print();
obj2.Print();
return0;
}
3、将任务2得到的正确程序分成3个文件。
文件MyClass.h包括类的定义,文件MyClass.cpp包括类成员函数的实现,文件App.cpp包括类的使用。
调试、运行该程序,使之获得正确结果。
4.已知两个矩形的长和宽,用面向对象的概念编程求它们的面积和周长。
假设矩形1的长和宽分别为20和50;矩形2的长和宽分别为3.6和4.5。
(先定义矩形类再实例化两个对象)
5.将教材7.1.3例题改造成面向对象的C++程序。
使用单链表来存储集合元素。
定义node类和Set类。
【实验指导】
1、头文件中通常包含常量、类型、函数原型的定义。
类是用户定义的类型,故将类的定义放在头文件中。
函数的定义即函数的实现应放在实现文件.cpp文件中。
这样的安排体现了信息隐藏和模块化。
将类成员函数的实现和类的使用放在不同的cpp文件中,可将类的实现与类的使用分离,体现了对接口编程的思想。
2、文件MyClass.h中的结构
#include
usingnamespacestd;
//MyClass的定义
文件MyClass.cpp中的结构
#include“MyClass.h”
//MyClass成员函数的定义
文件App.cpp中的结构
#include“MyClass.h”
//main函数的定义
3、避免头文件内容被重复引入。
头文件内容被重复引入会导致标识符重复定义的错误。
用预编译条件指令来限制头文件内容的引入。
例如:
#ifndefMYCLASS
#defineMYCLASS
//MyClass.h头文件的内容
#endif
说明:
#ifndef<标识>//如果没有定义<标识>#define<标识>//定义<标识>............#endif<标识>在理论上来说可以是自由命名的,但每个头文件的这个“标识”都应该是唯一的。
标识的命名规则一般是头文件名全大写,前后加下划线,
这样如果有两个地方都包含这个头文件,就不会出现两次包含的情况。
因为在第二次包含时<标识已经有定义了,所以就不再include了.
二、实验2:
数据抽象
【实验目的】
●掌握类的定义和使用以及类对象的声明和使用方法,理解具有不同访问属性的成员的访问方式。
●掌握构造函数和析构函数的作用和编写方法。
●了解并掌握静态成员、常成员的使用。
【实验内容】
1、下面程序中定义了一个整型动态数组,编写了3个构造函数。
#include
usingnamespacestd;
classIntArray{
public:
IntArray(intsz);//数组初始化为sz个元素,初值全为0
IntArray(int*array,intsz);//用静态数组array的前sz个元素初始化新数组
IntArray(constIntArray&rhs);//拷贝构造函数
voidprintAll();
private:
int*ia;
intsize;
};
IntArray:
:
IntArray(intsz){
size=sz;//设置数据成员
ia=newint[size];
for(intix=0;ixia[ix]=0;//初始化数组元素
}
IntArray:
:
IntArray(int*array,intsz){
size=sz;//设置数据成员
ia=newint[size];
for(intix=0;ixia[ix]=array[ix];//拷贝数据成员
}
IntArray:
:
IntArray(constIntArray&rhs)
{
size=rhs.size;
ia=newint[size];
for(intix=0;ixia[ix]=rhs.ia[ix];
}
voidIntArray:
:
printAll()
{
for(intix=0;ixcout<cout<}
intmain()
{
inta[10]={1,2,3,4,5,6,7,8,9,10};
IntArrayarr1(10),arr2(a,5),arr3(arr2);
arr1.printAll();
arr2.printAll();
arr3.printAll();
return0;
}
(1)为IntArray加上析构函数并编译运行程序,体会类的构造函数和析构函数的作用。
(2)程序中,类IntArray的三个构造函数都是以相似的方式来实现的。
一般来说,当两个或多个函数重复相同的代码时,可将这部分代码抽取出来,形成独立的函数,以便共享。
以后如果需要改变这些实现,则只需改变一次,而且这种实现的共享本质更容易为大家所理解。
怎样把构造函数中的代码抽取出来形成独立的共享函数呢?
请给出一种可能的实现。
按你给出的实现方法修改程序并重新编译运行。
2、设有一个点myPoint类的定义如下:
classmyPoint{
public:
myPoint(doublex0=0.0,doubley0=0.0):
x(x0),y(y0){}
myPoint(myPoint&np):
x(np.x),y(np.y){}
doubleGetX(){returnx;}
doubleGetY(){returny;}
voidSetX(doublex0){x=x0;}
voidSetY(doubley0){x=y0;}
voidSetPoint(doublex0,doubley0){x=x0;y=y0;}
voidSetPoint(myPoint&np){x=np.x;y=np.y;}
doubleGetLength(myPointp){
returnsqrt((x-p.x)*(x-p.x)+(y-p.y)*(y-p.y));
}
voidPrintit(){cout<<"("<private:
doublex,y;
};
试定义一个三角形Triangle类,在Triangle类中以点myPoint类的3个对象p1、p2、p3作为数据成员,表示三角形的三个顶点。
Triangle类具有计算三角形的周长和面积的功能。
请编写程序上机调试并运行。
3.编写栈类stack,要求栈类可以进行入栈和出栈操作,还可以查看栈顶元素的值。
栈类中的每个节点为一个类node对象。
Node类含有两个成员:
intdata,node*prev。
【实验指导】
1、
(1)可参考教材第192页关于“浅复制”和“深复制”的示例来实现析构函数的定义。
(2)在类中将构造函数的代码抽取出来形成独立的函数,然后在构造函数中调用执行,注意函数参数的设置和定义。
2、由于在Triangle类中需要定义myPoint类的对象,因此需要在Triangle类的构造方法的成员初始化列表中实现对成员对象的初始化。
三、实验3:
继承与多态性
【实验目的】
●掌握继承的概念,能够定义和使用类的继承关系。
●了解在派生类中如何使用基类的成员以及基类成员在派生类中的访问控制特性。
●理解虚基类在解决二义性问题中的作用。
●理解静态多态性和动态动态性的含义。
掌握使用虚函数和继承实现动态多态性的方法。
【实验内容】
1、有如下的程序:
#include
usingnamespacestd;
classBase
{
public:
Base(intp1,intp2){data1=p1;data2=p2;}
intInc1(){return++data1;}
intInc2(){return++data2;}
voidDisplay()
{cout<<"data1="<protected:
intdata1,data2;
};
classD1:
publicBase{
public:
D1(intp1,intp2,intp3):
Base(p1,p2){data3=p3;}
intInc1(){returnBase:
:
Inc1();}
intInc3(){return++data3;}
voidDisplay()
{
cout<<"data1="<cout<<"Base:
:
Display()----";
Base:
:
Display();
}
protected:
intdata3;
};
classD2:
publicBase{
public:
D2(intp1,intp2,intp4):
Base(p1,p2){data4=p4;}
intInc1()
{
Base:
:
Inc1();Base:
:
Inc2();
returnBase:
:
Inc1();
}
intInc4(){return++data4;}
voidDisplay()
{
cout<<"data1="<cout<<"Base:
:
Display()----";
Base:
:
Display();
}
protected:
intdata4;
};
classD12:
publicD1,publicD2{
public:
D12(intp11,intp12,intp13,intp21,intp22,intp23,intp)
:
D1(p11,p12,p13),D2(p21,p22,p23){data5=p;}
intInc1()
{D1:
:
Inc1();D2:
:
Inc1();
returnD1:
:
Inc1();
}
intInc5(){return++data5;}
voidDisplay()
{
cout<<"data1="<cout<<"data3="<cout<<"D1:
:
Display()----";
D1:
:
Display();
cout<<"D2:
:
Display()----";
D2:
:
Display();
}
private:
intdata5;
};
intmain()
{
D12d(1,2,3,4,5,6,7);
d.Display();
cout<d.Inc1();
d.Inc2();//②
d.Inc3();
d.Inc4();
d.Inc5();
d.D12:
:
Inc1();
d.Display();
return0;
}
(1)这个程序在编译时会出现错误,请根据出错提示信息找出出错的原因。
(2)修改程序中的错误,使之能正确运行。
2、设有一个点类Point的定义如下:
Point{
public:
Point(){x=0;y=0;}
Point(doublexv,doubleyv){x=xv;y=yv;}
Point(Point&pt){x=pt.x;y=pt.y;}
doublegetx(){returnx;}
doublegety(){returny;}
doubleArea(){return0;}
voidShow(){cout<<"x="<private:
doublex,y;
};
编写程序,以点point类为基类,派生出矩形类Rectangle和圆类Circle。
矩形由左上角的顶点和长、宽定义。
圆由圆心和半径定义。
派生类中新增的成员函数position(Point&pt)用于判断任一坐标点是在图形内、还是在图形的边缘上,还是在图形外。
3、设有几何图形的派生关系如下图14-2所示。
图14-2几何图形中类的继承关系
对平面图形可求周长和面积,对立体图形可以求体积以及底面图形的周长和底面积。
设有主函数如下:
intmain()
{
Geometric_shape*gs[]={newCircle(10),newRectangle(6,8),newTriangle(3,4,5),
newBox(6,8,3),newCylinder(10,3),newCone(10,3),newT_pyramid(3,4,5,3),newT_prism(3,4,5,3)};
for(inti=0;i<8;i++)
{
gs[i]->Show();
cout<}
for(i=0;i<8;i++)
{
gs[i]->Show();
cout<}
cout<<"平面图形:
"<for(i=0;i<3;i++)
{
cout<<"图形周长:
"<perimeter()<<'\t';
cout<<"图形面积:
"<area()<<'\t';
cout<<"图形体积:
"<volume()<}
cout<<"立体图形:
"<for(i=3;i<8;i++)
{
cout<<"图形底周长:
"<perimeter()<<'\t';
cout<<"图形底面积:
"<area()<<'\t';
cout<<"图形体积:
"<volume()<}
return0;
}
请编写各类的定义和实现代码,使给定的主函数main可以正确运行。
【实验指导】
1、在派生类中对基类成员的访问应该是唯一的。
但是,在有多重继承的情况下,可能会造成派生类对基类中某个成员的访问出现不唯一的情况,这时就称对基类成员的访问产生了二义性。
C++为此提供了虚基类,以解决这种二义性问题。
2、由于基类的构造函数不能够被派生类继承。
因此,派生类的构造函数必须通过调用基类的构造函数来初始化基类数据成员。
所以在定义矩形类Rectangle和圆类Circle的构造函数时,除了对新增数据成员进行初始化,还必须负责调用基类的构造函数使基类数据成员得以初始化。
同时,在矩形类Rectangle和圆类Circle还需分别提供计算面积、周长等函数,以满足实际应用的需求。
3、用虚函数来实现主程序中的动态联编。
即在Geometric_shape类中分别将计算面积、周长、体积等函数声明为虚函数后,就可以在该类的(直接或间接)派生类中定义与其基类虚函数原型相同的函数。
这时,当用基类指针指向这些派生类的对象时,系统会自动用派生类中的同名函数来代替基类中的虚函数,从而实现运行时的多态。
四、实验4:
重载和I/O流及面向对象程序设计
【实验目的】
●掌握运算符重载的基本方法。
●掌握标准输入输出的使用及格式控制方法。
●掌握磁盘文件(如二进制文件、文本文件)的输入输出的方法。
【实验内容】
1、编写程序,重载运算符“<<”和“>>”,使用户能直接输入和输出固定电话的号码。
电话号码以如下形式输入和输出:
(027)xxxxxxxx
2、编写一个程序,实现以下功能:
(1)输入一系列的学生成绩(包括学号、姓名、成绩等数据)存放在文件stud.dat中。
(2)从stud.dat文件中读出这些数据并显示出来。
(3)在stud.dat文件中按姓名进行查询,如输入“李”,则将所有姓李的学生的数据都显示出来。
所编写的程序运行结果示例如下:
选择(1:
输入数据2:
输出数据3:
按姓名查找数据其他退出):
1
输入数据
学生人数:
5
第1个学生(学号姓名成绩):
1001张三89
第2个学生(学号姓名成绩):
1002李四78
第3个学生(学号姓名成绩):
1003王五92
第4个学生(学号姓名成绩):
1004李沅芷88
第5个学生(学号姓名成绩):
1005赵六56
选择(1:
输入数据2:
输出数据3:
按姓名查找数据其他退出):
2
输出数据
学号姓名成绩
1001张三89
1002李四78
1003王五92
1004李沅芷88
1005赵六56
选择(1:
输入数据2:
输出数据3:
按姓名查找数据其他退出):
3
输入姓名:
李
输出匹配的结果:
学号姓名成绩
1002李四78
1004李沅芷88
选择(1:
输入数据2:
输出数据3:
按姓名查找数据其他退出):
3
输入姓名:
李四
输出匹配的结果:
学号姓名成绩
1002李四78
选择(1:
输入数据2:
输出数据3:
按姓名查找数据其他退出):
0
4.栈是一种重要的数据结构,它是一种只允许在表的一端进行插入或删除操作的线性表。
表中允许进行插入、删除操作的一端称为栈顶。
表的另一端称为栈底。
栈顶的当前位置是动态的,对栈顶当前位置的标记称为栈顶指针。
当栈中没有数据元素时,称之为空栈。
栈的插入操作通常称为进栈或入栈,栈的删除操作通常称为退栈或出栈。
下面是一个整型栈类的定义:
constintMaxSize=100;//栈中能保存的最多元素个数
classIStack
{
public:
Istack();//栈的构造函数
voidPush(int&n);//往栈顶增加元素
voidPop();//从非空栈的栈顶删除一个元素
intGetTop();//返回非空栈的栈顶元素
boolEmpty();//判断栈是否为空
intSize();//返回栈中元素的个数
voidClearStack();//将栈清空
~Istack();//栈的析构函数
private:
intelem[MaxSize];//保存栈中各元素的数组
intTop;//保存栈顶的当前位置
}
试编写一个栈的类模板(包括其成员函数的实现),以便为任何类型的对象提供栈结构的数据操作。
然后在main()实现栈的各种操作。
【实验指导】
1、在重载运算符“<<”和“>>”时,不能将其定义为类的成员函数,只能定义为类的友元函数。
2、在进行输入输出时,程序中如果使用带参数的操纵符,必须使用预编译命令
#include
将需要的头文件包含进来。