实验8 多态性与虚函数

合集下载

第8章 多态性和虚函数

第8章 多态性和虚函数

第8章多态性和虚函数封装性基础面向对象系统三特征继承性关键多态性补充多态性是指发出同样的消息被不同类型的对象接收时导致完全不同的行为。

这里所说的消息主要是指对类的成员函数的调用,而不同的行为是指不同的实现。

利用多态性,用户只需发送一般形式的消息,而将所有的实现留给接收消息的对象。

多态的类型:简单的多态性是函数重载和运算符重载。

重要的多态性是建立在虚函数的概念和方法上的。

8.1 函数重载8.2 运算符重载运算符重载就是赋予已有的运算符多重含义,使它能够用对类的对象进行特定的操作。

8.2.1运算符重载的几个问题1.C++中不能重载的运算符是:. , .* ,:: , ?:2.运算符重载不改变原运算符的优先级和结合性。

3.编译程序对运算符重载的选择,遵循函数重载的原则。

4.重载运算符的限制:(1)不可臆造新的运算符。

(2)重载运算符坚持4个“不能改变”。

·不能改变运算符操作数的个数;·不能改变运算符原有的优先级;·不能改变运算符原有的结合性;·不能改变运算符原有的语法结构。

5.运算符重载时必须遵循哪些原则:(1)重载运算符含义必须清楚。

(2)重载运算符不能有二义性。

8.2.2 运算符重载的两种形似运算符重载的两种形式:成员函数形式和友元函数形式。

1.重载为类的成员函数例8.2复数类四则运算重载#include<iostream.h>class complex{ public:complex( ) { real=imag=0; }complex(double r, double i){real=r,imag=i;}complex operator +(const complex &c);complex operator -(const complex &c);complex operator *(const complex &c);complex operator /(const complex &c);friend void print(const complex &c);private:double real,imag;};inline complex complex::operator +(const complex &c) { return complex(real+c.real,imag+c.imag); }inline complex complex::operator -(const complex &c) { return complex(real-c.real,imag-c.imag); }inline complex complex::operator *(const complex &c) { return complex(real * c.real-imag * c.imag,real * c.imag+imag * c.real); }inline complex complex::operator /(const complex &c) { return complex((real * c.real + imag + c.imag)/ (c.real*c.real+c.imag*c.imag),(imag* c.real - real * c.imag)/(c.real * c.real + c.imag *c.imag)); }void print(const complex &c){ if(c.imag<0)cout<<c.real<<c.imag<<'i';elsecout<<c.real<<'+'<<c.imag<<'i';}void main( ){ complex c1(2.0,3.0),c2(4.0,-2.0),c3;c3=c1+c2;cout<<"\nc1+c2=";print(c3);c3=c1-c2;cout<<"\nc1-c2=";print(c3);c3=c1*c2;cout<<"\nc1*c2=";print(c3);c3=c1/c2;cout<<"\nc1/c2=";print(c3);c3=(c1+c2)*(c1-c2)*c2/c1;cout<<"\n(c1+c2)*(c1-c2)*c2/c1=";print(c3);cout<<endl;}该程序的运行结果为:c1+c2=6+1ic1-c2=-2+5ic1*c2=14+8ic1/c2=0.45+0.8i(c1+c2)*(c1-c2)*c2/c1=9.61538+25.2308i小结:1.在程序中,定义了4个成员函数作为运算符重载函数。

翟C++第08章 多态性和虚函数

翟C++第08章  多态性和虚函数

}
void fun(B0 *ptr) //普通函数 { ptr -> display ( ); } void main ( ) { B0 b0, *p; //声明基类对象和指针 B1 b1; //声明派生类对象 D1 d1; //声明派生类对象 p=&b0; fun(p); //调用基类B0函数成员 p=&b1; fun(p); //调用派生类B1函数成员 p=&d1; fun(p); //调用派生类D1函数成员
class Square:public base { public: void disp() { cout<< "x="<< x <<":"; cout<< "x square="<< x*x << endl; } }; class Cube:public base {public: void disp() { cout<< “x=”<< x <<“:”; cout<< "x cube="<< x*x*x << endl; } };
#include <iostream.h> class B0 {public: void display ( ) {cout<<"B0::display ( ) "<<endl;} }; class B1: public B0 { public: void display( ) { cout<<"B1::display ( ) "<<endl; }; class D1: public B1 { public: void display ( ) { cout<<"D1::display ( ) "<<endl; } };

8 多态性和虚函数

8 多态性和虚函数

注意: ① 定义为内联函数
② 形参为complex 类的常引用,目的: 保证引用的complex 对象值不变
8.2 运算符重载
友元函数
8.2 运算符重载
c1.real=2.0 c1.imag=3.0 c2.real=4.0c2.imag=-2.0 c3.real=0 c3.imag=0
8.2 运算符重载
8.2 运算符重载
运算符重载
• 为什么要进行运算符重载: 使原有的运算符能够用于用户自定义类 例:class complex; //用户自定义一个复数类 { …}; complex com1,com2; //定义两个复数 com1+com2 ? com1-com2 ? ……
8.2 运算符重载
运算符重载
8.1 函数重载
– 字符串可调用的操作函数(即string类的成员函 数)(共23个函数):
assign( ) //为字符串赋新值 swap( ) //交换两个字符串的内容 append( ) //在字符串尾部添加字符 insert( ) //插入字符 erase( ) //删除字符 clear( ) //删除全部字符 compare( ) //比较字符串 size( ),length( ) //返回字符数量 empty( ) //判断字符串是否为空 …… //其它操作请见C++类库文档

8.2 运算符重载
c1.real=2.0 c1.imag=3.0 c2.real=4.0c2.imag=-2.0 c3.real=14.0c3.imag=8.0 c3.real=-2.0c3.imag=5.0 c3.real=0.1 c3.imag=0.8 c3.real=6.0 c3.imag=1.0 c3.real=0 c3.imag=0

c++多态性与虚函数习题答案

c++多态性与虚函数习题答案

多态性与虚函数1.概念填空题1.1 C++支持两种多态性,分别是编译时和运行时。

1.2在编译时就确定的函数调用称为静态联编,它通过使用函数重载,模板等实现。

1.3在运行时才确定的函数调用称为动态联编,它通过虚函数来实现。

1.4虚函数的声明方法是在函数原型前加上关键字virtual。

在基类中含有虚函数,在派生类中的函数没有显式写出virtual关键字,系统依据以下规则判断派生类的这个函数是否是虚函数:该函数是否和基类的虚函数同名;是否与基类的虚函数参数个数相同、类型;是否与基类的虚函数相同返回类型。

如果满足上述3个条件,派生类的函数就是虚函数。

并且该函数覆盖基类的虚函数。

1.5 纯虚函数是一种特别的虚函数,它没有函数的函数体部分,也没有为函数的功能提供实现的代码,它的实现版本必须由派生类给出,因此纯虚函数不能是友元函数。

拥有纯虚函数的类就是抽象类类,这种类不能实例化。

如果纯虚函数没有被重载,则派生类将继承此纯虚函数,即该派生类也是抽象。

3.选择题3.1在C++中,要实现动态联编,必须使用(D)调用虚函数。

A.类名B.派生类指针C.对象名D.基类指针3.2下列函数中,不能说明为虚函数的是(C)。

A.私有成员函数B.公有成员函数C.构造函数D.析构函数3.3在派生类中,重载一个虚函数时,要求函数名、参数的个数、参数的类型、参数的顺序和函数的返回值(A)。

A.相同B.不同C.相容D.部分相同3.4当一个类的某个函数被说明为virtual时,该函数在该类的所有派生类中(A)。

A.都是虚函数B.只有被重新说明时才是虚函数C.只有被重新说明为virtual时才是虚函数D.都不是虚函数3.5(C)是一个在基类中说明的虚函数,它在该基类中没有定义,但要求任何派生类都必须定义自己的版本。

A.虚析构函数B.虚构造函数C.纯虚函数D.静态成员函数3.6 以下基类中的成员函数,哪个表示纯虚函数(C)。

A.virtual void vf(int);B.void vf(int)=0;C.virtual void vf( )=0;D.virtual void vf(int){ }3.7下列描述中,(D)是抽象类的特性。

多态性与虚函数.doc

多态性与虚函数.doc

多态性与虚函数多态性的概念多态性(polymorphism)是面向对象程序设计的一个重要特征。

利用多态性可以设计和实现一个易于扩展的系统。

有过非面向对彖语言开发经历的人,通常对这一章节的内容会觉得不习惯,因为很多人错误地认为,支持类的封装的语言就是支持血向对象的,其实不然,Visual BASIC 6.0是典型的非面向对象的开发语言,但是它的确是支持类,支持类并不能说明就是支持面向对象,能够解决多态问题的语言,才是真正支持面向对象的开发的语言,所以务必提醒有过其它非面向对象语言基础的读者注意!多态的意思是指具有不同功能的函数可以用同一个函数名,这样就可以用一个函数名调用不同内容的函数。

其实,我们己经接触过多态性的现象,例如函数的重载、运算符重载都是多态现象。

只是那时没有用到多态性这一专业术语而已。

例如,使用运算符”+”使两个数值相加,就是发送一个消息,它要调用operator+函数。

实际上,整型、单精度型、双精度型的加法操作过程是互不相同的,是由不同内容的函数实现的。

显然,它们以不同的行为或方法來响应同一消息。

在面向对象方法中一般是这样表述多态性的:向不同的对象发送同一个消息,不同的对象在接收时会产生不同的行为(即方法)。

也就是说,每个对象可以用自己的方式去响应共同的消息。

从系统实现的角度看,多态性分为两类:静态多态性和动态多态性。

以前学过的函数重载和运算符重载实现的多态性属于静态多态性,在程序编译时系统就能决定调用的是哪个函数,因此静态多态性乂称编译时的多态性。

静态多态性是通过函数的重载实现的(运算符重载实质上也是函数重载)。

动态多态性是在程序运行过稈中才动态地确泄操作所针对的对彖。

它又称运行时的多态性。

动态多态性是通过虎函数(virtual function)实现的。

本章中主要介绍动态多态性和虚函数。

要研究的问题是:当一个基类被继承为不同的派生类时,各派生类可以使用与基类成员相同的成员名,如果在运行时用同一个成员名调用类对象的成员,会调用哪个对象的成员?也就是说,通过继承而产生了相关的不同的派生类,与基类成员同名的成员在不同的派生类中有不同的含义。

多态性和虚函数设计

多态性和虚函数设计
}
for(vector<Shape*>::iterator it=va.begin(); it!=va.end(); ++it)
(*it)->Display();
system("pause");
}
【实验结果】
【教师评语和成绩】
成绩:指导教师:日期:
输入文件shape.txt如下:
C 123 5 10
C 6 61 20
R 6 8 8 10
C 2 3 1
X
若第一个字符为'C',则后面为圆的数据
若第一个字符为'R',则后面为长方形的数据
若第一个字符为'X',表示输入结束
int main(){
vector<Shape*> va;
ifstream in("shape.txt");
Shape *ps;
char s;
double a,b,c,d,e,f;
for(;in>>s && s!='X' ;){
if(s=='C'){in>>a>>b>>c;ps=new Circle(a,b,c); va.push_back(ps);}
else if(s=='R'){
in>>a>>b>>c>>d;
姓名:
专业:
班级:
学号:
科目:
实验日期:
实验题目:多态性和虚函数设计
【实验目的】
1.在掌握继承与派生关系的基础上,进一步理解虚函数与多态性的关系,实现运行时的多态性。

多态性与虚函数实验报告

多态性与虚函数实验报告
{
cout<<"三角形的底为:"<<width<<"高为:"<<height <<"面积为:"<<width*height/2<<endl;
}
private:
float width,height;
};
class Circle:public Base
{
public:
Circle(float r){radius = r;}
p= &obj1;
p->area();
p=&obj2;
p->area();
return 0;
}
【实验结果与数据处理】
【实验结论】
分析:用虚函数实现多态。
【实验器材】
微型计算机、Visual C++ 6.0集成软件平台
【实验步骤】
1.编辑源程序。
2.对源程序进行编译并调试程序。
3.连接并运行程序。
4.检查输出结果是否正确。程序设计如下:
#include<iostream.h>
const float PI = 3.14;
class Base
多态性与虚函数实验报告
实验题目
多态性与虚函数
日期
班级
组别
姓名
类型
【实验目的】
1.理解多态性的概念。
2.了解编译时的多态和运行时的多态。
3.掌握虚函数的定义及实现,掌握虚析构函数的使用方法。
4.了解纯虚函数和抽象类的关系及用法。
【实验原理】
设计一个基类Base,其作用是计算一个图形的面积,它只有一个公有的函数成员虚函数area。再从Base类公有派生一个三角形类Triangle和一个圆类Circle,在类Triangle和类Circle中分别定义自己的area函数,用于计算各自的面积。在主函数中设计一个Base类的对象指针,分别指向类Triangle和类Circle的对象,调用各自的area函数显示相应对象的面积。

多态性与虚函数实验报告

多态性与虚函数实验报告

多态性与虚函数实验报告实验目的:通过实验掌握多态性和虚函数的概念及使用方法,理解多态性实现原理和虚函数的应用场景。

实验原理:1.多态性:多态性是指在面向对象编程中,同一种行为或者方法可以具有多种不同形态的能力。

它是面向对象编程的核心特性之一,能够提供更加灵活和可扩展的代码结构。

多态性主要通过继承和接口来实现。

继承是指子类可以重写父类的方法,实现自己的特定行为;接口是一种约束,定义了类应该实现的方法和属性。

2.虚函数:虚函数是在基类中声明的函数,它可以在派生类中被重新定义,以实现多态性。

在类的成员函数前面加上virtual关键字,就可以将它定义为虚函数。

当使用基类指针或引用调用虚函数时,实际调用的是派生类的重写函数。

实验步骤:1. 创建一个基类Shape,包含两个成员变量color和area,并声明一个虚函数printArea(用于打印面积。

2. 创建三个派生类Circle、Rectangle和Triangle,分别继承Shape类,并重写printArea(函数。

3. 在主函数中,通过基类指针分别指向派生类的对象,并调用printArea(函数,观察多态性的效果。

实验结果与分析:在实验中,通过创建Shape类和派生类Circle、Rectangle和Triangle,可以实现对不同形状图形面积的计算和打印。

当使用基类指针调用printArea(函数时,实际调用的是派生类的重写函数,而不是基类的函数。

这就是多态性的实现,通过基类指针或引用,能够调用不同对象的同名函数,实现了对不同对象的统一操作。

通过实验1.提高代码的可扩展性和灵活性:通过多态性,可以将一类具有相似功能的对象统一管理,节省了代码的重复编写和修改成本,增强了代码的可扩展性和灵活性。

2.简化代码结构:通过虚函数,可以将各个派生类的不同行为统一命名为同一个函数,简化了代码结构,提高了代码的可读性和维护性。

3.支持动态绑定:通过运行时的动态绑定,可以根据对象的实际类型来确定调用的函数,实现了动态绑定和多态性。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

b)
c)Leabharlann 根据是 Bicycle 还是 Motocar 输入 height 或者 seatNum。
(4)main 中的输出: 建立循环(for 0 ~ N-1) 。在循环中: 检测指针数组中 pvehicle[i](第 i 个指针)是否为空? 调用虚函数 print()输出属性。 (因为有动态联编, 所以不用区分是 Bicycle 还是 Motocar) 。 (5)main 中释放空间: 将指针数组 pvehicle[]中非空指针释放空间(用 delete) 。
parkingSpace[i]->record(licensetag); // 车辆登记 CampusAutos::ShowCurAutos(parkingSpace); break; } } if(i==N) cout << "Parking Space No." << i << "is available.\n"; continue; } else if ( choice == 2 ) // 车辆退出 { if( CampusAutos::count <= 0 ) // 车位是否已空 { cout<<"Parking Space is empty!\n"<<endl; continue; } for(;;) // 车位不为空时的退出操作 { char licensetag[80]; CampusAutos::inputLicensetag(licensetag); for(int i=0;i<N;i++) // 检查是否有此车 if( parkingSpace[i] != null && parkingSpace[i]->isSameAs(licensetag) ) break; if ( i==N ) // 没发现此车,输入有误,重新输入 cout << "No such licensetag! Retry.\n"; else // 该车是编号为 i 车位的车 { delete parkingSpace[i]; // 删除该对象 parkingSpace[i] = null; // 该车位指针置空 break; // 退出循环 } CampusAutos::ShowCurAutos(parkingSpace); } } else if ( choice == 0 ) // 程序结束 { for(int i=0;i<N;i++) // 释放申请空间 if( parkingSpace[i] != null ) delete parkingSpace[i]; break; // 退出循环 } else { cout << "Error choice. Retry.\n";
} } }
4. 按要求为 Complex 类重载以下几个运算符函数,并在主函数中进行测试。 1) 赋值=:重载为成员函数(必须) 2) 加号-: 重载为友元函数 3) 前置++:重载为友元函数 4) 后置++:重载为友员函数 5) 判断相等= = : 重载为友元函数 class Complex { double real; double imag; public: Complex(double real=0,double imag=0); Complex(Complex &r); ~Complex(); void SetComplex(double real=0,double imag=0); void Print(); }; Complex::~Complex() { } Complex::Complex(double real/* =0 */,double imag/* =0 */) { this->real=real; this->imag=imag; } Complex::Complex(Complex &r) { real=r.real; imag=r.imag; } void Complex::SetComplex(double real/* =0 */,double imag/* =0 */) { this->real=real; this->imag=imag; }
void Complex::Print() { cout<<real<<"+"<<imag<<"j"<<endl; } 4. 临时对象:某些时候会创建生存期在一条语句范围的无名对象,称之为临时对象。在以 下场合下会创建临时对象: a) 非初始化语句中显式调用类的构造函数时 Student(“zhang”); Student s; s=Student(“ zhang”); Student t[3]; t[0]=Student(“zhang”); Student Test(Student s){return Student(“ zhang”);} 非初始化语句中对象作返回值函数返回时 Student Test(){Student s; return s;} Student t; t=Test(); 新版 VC 编译器中,临时对象如果用于在初始化语句中初始化新对象,则不再创建 临时对象: Student s=Student(“ zhang”); Student s1(Student(“zhang”)); //前面两句等同于 Student s(“ zhang”);只调用 1 次有参构造 Student s2[3]={Student(“ zhang”)};//本句调用 1 次有参构造,2 次无参构造 Student Test(Student s){ return s;} Test(Student(“zhang”)); Student t= Test(Student(“ zhang”));
实验八 多态性与虚函数
实验目的
了解多态性的两种表现形式:函数重载和虚函数 了解赋值兼容原则的含义 掌握虚函数的定义方法及作用
一、实验任务: 1. 虚函数练习 (1)设计一个抽象类 Shape,其中包括 double area 和 double Area(); (2)以 public 方式从 Shape 派生出 Circle 和 Rectangle 两个派生类,添加相关的数据成 员(Circle: radius,PI; Rectangle:width,height) 、有参构造函数、重写 Area 函数; (3)设计主函数:要求定义一个 4 元素 Shape 类指针数组,数组元素初始化为 NULL, 动态创建 2 个 Circle 对象和 2 个 Rectangle 对象,用上面的指针数组操作 4 个对象,设 计循环求算它们的面积总和。 调试程序,分析理解虚函数动态联编的原理。 2. 自行车(Bicycle)和汽车(Motorcar)都是车辆(Vehicle) ,它们有共同的属性最大速度 (maxSpeed)和重量(weight) ,也有各自不同的特性,比如自行车的高度(height)和 汽车的座位数(seatNum) 。现有车辆若干(实验时设 N=3) ,将其输入并放入一个指针 数组,每个车辆需要设置其属性。输入后分类显示各自属性(即自行车和汽车分别显示 各自属性) 。 (1)基本思路: 创建类 Vehicle 及其派生类;设基类为 Vehicle,具有属性 maxSpeed 和 weight,其中有 一个虚函数 print 显示属性, 由派生类负责解释具体的属性。 由 Vehicle 派生两个类 Bicycle 和 Motocar,Bicycle 的属性为 height;而 Motocar 的属性为 seatNum。 (2)main 中创建指针数组:main 中创建一个指针数组 Vehicle* pvehicle[N];并将其中指 针置空。 (3)main 中的输入: 用一个循环次数少于 N 的循环(while 或 for)下面是循环中进行的工作: 询问用户是 Bicycle 还是 Motocar,或者退出循环? 如果是 Bicycle 则创建 Bicycle 的堆对象;否则创建 Motocar 的堆对象 vcl。 (使用 new) 将该对象的地址记录到指针数组 pvehicle[]的空白处。 (也可先找到这个空白处,再 创建堆对象) 询问用户新输入的车辆的 maxSpeed 和 weight,将这两个参数记录到这个对象 vcl 中。
3. 某学校实现进出校园的车辆管理, 试用类的形式记录车辆的进出 (类名为 CampusAutos) 。 有车进来时用 new 的方法构建一个新的对象,记录它的牌照( 8 个字符的字符串, licensetag) ,离开校园时即析构。在 main()中设一循环,每次可以输入车辆进入及牌照 号或某牌照号的车辆出去(校园内限 N 辆,暂设为 5) ,同时报告校园内现有多少辆汽 车及它们的牌照号。 (用对象指针数组) 注意: 程序中要实现数组溢出保护 (车位已满) 、 牌照输入错误(超 8 个字符)和查询失败报告(无此牌照) 。停车时要注意重复车牌问 题。 void main() { CampusAutos *parkingSpace[N]; for(int i=0;i<N;i++) // 停车场初始化为空 parkingSpace[i] = null; for(;;) { cout << "1 --- Auto Enter\n2 -- Auto Exit\n0 -- End\nYour Choice:"; int choice; cin >> choice; if ( choice == 1 ) // 车辆进入 { if( CampusAutos::count >= N ) // 车位是否已满 { cout<<"Parking space is full!\n"<<endl; continue; } for (int i=0; i < N; i++ ) { if( parkingSpace[i] == null ) // 寻找空位 { parkingSpace[i] = new CampusAutos(); // 创建新的停车位 char licensetag[80]; CampusAutos::inputLicensetag(licensetag);
相关文档
最新文档