当前位置:文档之家› 实验8_继承和多态

实验8_继承和多态

实验08:继承与多态实验学时:6实验类型:验证、设计实验要求:必修一、实验目的1.理解继承的概念,了解面向对象设计中继承和多态的合理性;2.掌握派生类的构造与析构;3.掌握在对象中使用类层次和继承思想进行设计、实现和测试;4.区别运行时的多态性的实现,理解重载与同名覆盖的差异;5.理解虚函数与多态性;6.实现运行时多态性的程序设计。

二、实验内容1.Difine a class called PartFileledArrayWMax that is a derived class of the class PartFilledArray. The class PartFilledArrayWMax has one additional member variable named max_value that holds the maximum value stored in the array. Define a member accessor function named get_max that returns the maximum value stored in the array. Redefine the member function add_value and define two constructors, one of which has an int argument for the maximum number of entries in the array. Also define a copy constructor, an overloaded assignment operator, and a destructor. (A real class would have more member functions, but these will do for an exercise.)2.某公司雇员(employee)包括经理(Manager)、技术人员(Technician)和销售员(Saleman)。

开发部经理(developermanager)既是经理也是技术人员,销售部经理(salesmanager)既是经理也是销售员。

以employee类为虚基类,派生出manager、technician和saleman类,再进一步派生出developermanager和salesmanager类。

Employee类的属性包括姓名、职工号、工资级别、月薪(实发基本工资加业绩工资);操作包括月薪计算函数pay(),该函数要求输入请假天数,扣除应扣工资后,得出实发基本工资。

Technician类派生的属性有每小时附加酬金和当月工作时数,以及研究完成进度系数,业绩工资为三者之积。

也包括同名的pay函数,工资总额为基本工资加业绩工资。

Saleman类派生的属性有当月销售额和酬金提取百分比,业绩工资为两者之积。

也包括同名的pay函数,工资总额为基本工资加业绩工资。

Manager类派生的属性有固定奖金额和业绩系数,业绩工资为两者之积。

工资总额也为基本工资加业绩工资。

而在developermanager类中,pay函数是将作为经理和作为技术人员业绩工资之和的一半作为业绩工资。

在salesmanager类中,pay函数则是经理的固定奖金额的一半,加上部门总销售额与提成比例之积,这是业绩工资。

编程实现工资管理。

特别注意pay()的定义和调用方法:先用同名覆盖,再用运行时多态。

3.继承范例:定义一个继承与派生关系的类体系,在派生类中访问基类成员。

[要求]定义一个点类,包含x,y 坐标数据成员,显示函数和计算面积的函数成员;以点为基类派生一个圆类,增加表示半径的数据成员,重载显示和计算面积的函数;定义一个直线类,以两个点类对象作数据成员,定义显示、求面积及长度函数。

编程测试所定义的类体系。

[程序]#include <iostream.h>#include <math.h>#define PI 3.14159class Point{friend class Line;protected:double x, y ;public:Point(){x = 0 ; y = 0 ; }Point(double xv,double yv){ x = xv; y = yv; }double Area(){return 0;}void Show() {cout<<"x="<<x<<' '<<"y="<<y<<endl;}};class Circle :public Point{double radius;public:Circle(){ x = 0; y = 0; radius = 0; }Circle(double xv,double yv,double vv):Point(xv,yv){ //调用基类构造函数radius = vv;}double Area(){return PI*radius*radius;}void Show(){//访问基类的数据成员cout<<"x="<<x<<' '<<"y="<<y<<"radius="<<radius<<endl;}};class Line{Point start,end; //对象成员public:Line():start(0,0),end(0,0){ } //对象成员初始化Line(double xv1,double yv1,double xv2,double yv2) :start(xv1,yv1),end(xv2,yv2){ }double GetLength() {return sqrt((start.x-end.x)*(start.x-end.x)+(start.y-end.y)*(start.y-end.y));}double Area(){return 0;}void Show(){cout<<"start point:\n";start.Show();cout<<"end point:\n";end.Show();}};void main(){Point pt(0,0);Circle cl(100,100,10);Line ln1(0,0,100,100);cout<<pt.Area()<<endl;pt.Show();cout<<cl.Area()<<endl;cl.Show();cout<<ln1. Area()<<'\t'<<ln1. GetLength()<<endl;ln1.Show();}[注意]在Point 类中,将Line 类定义为友元,方便在Line 中访问;Point 的x 和y 定义为Protected访问权限,便于派生类访问。

注意派生类的构造函数中对基类数据成员的初始化方法,以及构造函数中对对象成员的初始化。

[要求]1) 建立工程,录入上述程序,改变数据实验之。

2) 修改CPoint 类数据成员x,y 的访问权限为private,再运行,结果如何?3) 如果不将CLine 设为CPoint 的友元,应采取什么措施?为哪个类增加数据或函数成员?4.多态范例定义一个抽象基类CElement,提供显示、求面积等公共接口(虚函数),派生出CPoint、CLine、CCircle、CArc 等图形元素类,并重定义(override)这些虚函数,完成各自的任务。

再定义一个CElemList 链表类,存储CElement 的派生类。

然后定义main 函数,生成多个图形元素插入链表中,通过链表的头指针逐个访问链表中的元素,输出所有图形元素。

在这里,CElement 是抽象基类,它不能提供具体的显示等操作,应将其成员函数定义为纯虚函数。

只有采用指向基类的指针或对基类的引用进行调用,实现的才是动态联编,完成运行时的多态性。

[程序]//element.h#include <math.h>double const PI=3.14159class CElement {public:virtual void Show()=0;virtual double Area() = 0;CElement *Next;};class CPoint:public CElement{friend class CLine;protected:double x,y;public:CPoint(){x = 0; y = 0; }CPoint(double xv,double yv){x = xv;y = yv;}double Area(){return 0;}void Show(){cout<<"x="<<x<<' '<<"y="<<y<<endl;}};class CCircle :public CPoint{double radius;public:CCircle(){ x = 0; y = 0; radius = 0; }CCircle(double xv,double yv,double vv):CPoint(xv,yv){radius = vv;}double Area(){return PI*radius*radius;}void Show(){cout<<"x="<<x<<' '<<"y="<<y<<' '<<"radius="<<radius<<’ ’<<”Area=”<<Area()<<endl;}};class CLine:public CElement{CPoint start,end;public:CLine():start(0,0),end(0,0){}CLine(double xv1,double yv1,double xv2,double yv2):start(xv1,yv1),end(xv2,yv2){ };double GetLength(){return sqrt((start.x-end.x)*(start.x-end.x)+(start.y-end.y)*(start.y-end.y)); }double Area(){return 0;}void Show(){cout<<"start point:\n";start.Show();cout<<"end point:\n";end.Show();cout<<”Length=”<<GetLength()<<endl;}};class CElemList{protected:CElement *head; // 链表头指针定义为基类类型public:CElemList():head(NULL){}~CElemList();void Insert(CElement *); // 插入元素int Delete(CElement *); // 删除元素void Show(); // 显示所有元素CElement* GetHead(){ return head; } // 取得链表头};//element.cpp#include <iostream.h>#include "element.h"CElemList::~CElemList(){CElement *p = head,*p2;while(p){p2 = p;p = p->Next;delete p2;}return ;}void CElemList::Insert(CElement *elem){elem->Next = head; // 在表头插入结点head = elem;}int CElemList::Delete(CElement * elem){CElement *p1 = head,*p2 = head;while(p1&&p1!=elem)p2 = p1,p1 = p1->Next;if(p1==elem){if(p1!=head) p2->Next = p1->Next;else head = head->Next;delete p1;return 1;}else return 0;}void CElemList::Show(){CElement *p = head;while(p){ // 通过基类指针调用派生类成员函数,实现运行时多态性p->Show();p = p->Next;}return ;}//exp16_1.cpp#include <iostream.h>#include "element.h"void main(){CElemList list; // 定义链表类对象CElement *p1 = new CLine(100,100,100,200);list.Insert(p1);list.Show();cout<<endl;p1 = new CCircle(200,100, 20);list.Insert(p1);list.Show();cout<<endl;list.Delete(p1);list.Show();cout<<endl;}[要求]1) 建立工程,录入上述程序,改变数据实验之。

相关主题