实验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.支持动态绑定:通过运行时的动态绑定,可以根据对象的实际类型来确定调用的函数,实现了动态绑定和多态性。

C++面向对象程序设计》实验报告

C++面向对象程序设计》实验报告

《C++面向对象程序设计》实验内容实验1 C++程序设计初步1.实验目的(1)了解在C++编译系统(Visual C++6.0)上如何编辑、编译、连接和运行一个C++程序。

(2)通过运行简单的C++程序, 初步了解C++源程序的结构和特点。

(3)掌握简单C++程序的编写和调试方法。

(4)掌握重载函数的定义方法。

(5)能正确使用引用型变量。

2.实验内容和步骤(1)在Visual C++环境下编译和运行C++程序①先进入Visual C++6.0环境。

②在自己指定的子目录中建立一个名为test.cpp的新文件。

③从键盘输入以下程序int main(){int a,b;c=a+b;cout>> “a+b=”>>a+b;}选择Build→Compile test.cpp命令, 对此源程序进行编译。

观察和分析编译信息。

⑤根据编译信息指出的错误, 修改程序。

再进行编译, 如果还有错, 再重复此过程, 直到编译不出错为止。

⑥选择Build→Build test.exe命令, 对程序进行连接, 如果不出错, 就会生成可执行程序test.exe。

⑦选择Build→Execute test.exe命令, 执行可执行程序test.exe。

观察屏幕的变化。

在输出窗口应显示程序运行结果。

⑧分析结果是否正确, 如果不正确或认为输出格式不理想, 可以修改程序, 然后重新执行以上④和⑧步骤。

改过后的程序:#include<iostream>using namespace std;int add(int x,int y){int z;z=x+y;return(z);}int main(){int a,b,c;cin>>a>>b;c=add(a,b);cout<<"a+b="<<c<<endl;return 0;}实验2 C++对C的扩充(2)编一个程序, 用来求2个或3个正整数中的最大数。

多态性和虚函数 实验报告

多态性和虚函数 实验报告

多态性和虚函数实验报告淮海工学院计算机科学系实验报告书课程名:《 C++程序设计(二)》题目:多态性和虚函数班级:学号:姓名:评语:成绩:指导教师:批阅时间:年月日 C++程序设计实验报告1、实验内容或题目(1)声明二维坐标类作为基类派生圆的类,把派生类圆作为基类,派生圆柱体类。

其中,基类二维坐标类有成员数据:x、y坐标值;有成员函数:构造函数实现对基类成员数据的初始化、输出的成员函数,要求输出坐标位置。

派生类圆类有新增成员数据:半径(R);有成员函数:构造函数实现对成员数据的初始化、计算圆面积的成员函数、输出半径的成员函数。

派生圆柱体类新增数据有高(H);新增成员函数有:构造函数、计算圆柱体体积的函数和输出所有成员的函数。

请完成程序代码的编写、调试。

(2)教材393页7-8题。

(3)教材416页1、4、5题。

2、实验目的与要求(1)理解继承与派生的概念(2)掌握通过继承派生出一个新的类的方法(3)了解多态性的概念(4)了解虚函数的作用与使用方法3、实验步骤与源程序⑴ 实验步骤先定义一个基类point,及其成员函数,然后以public的继承方式定义子类circle,再定义一个派生类cylinder,最后在main主函数中定义类对象,调用函数实现其功能。

先定义一个基类A及其重载的构造函数,然后以Public派生出子类B,再定义其构造函数,最后在main主函数中定义类对象,调用成员函数实现其功能。

⑵ 源代码1.#include class Point { public:Point(float=0,float=0); void setPoint(float,float); float getX() const {return x;}C++程序设计实验报告float getY() const {return y;}friend ostream & operator<protected: };Point::Point(float a,float b) {x=a;y=b;}void Point::setPoint(float a,float b) {x=a;y=b;}ostream & operator<class Circle:public Point { public:Circle(float x=0,float y=0,float r=0); void setRadius(float); float getRadius() const; float area () const;friend ostream &operator<protected: };Circle::Circle(float a,float b,float r):Point(a,b),radius(r){}float radius;C++程序设计实验报告void Circle::setRadius(float r) {radius=r;}float Circle::getRadius() const {return radius;}float Circle::area() const {return 3.14159*radius*radius;}ostream &operator<cout<class Cylinder:public Circle { public:Cylinder (float x=0,float y=0,float r=0,float h=0); void setHeight(float); float getHeight() const; float area() const; float volume() const;friend ostream& operator<r=\protected: };Cylinder::Cylinder(float a,float b,float r,floath):Circle(a,b,r),height(h){}float height;C++程序设计实验报告void Cylinder::setHeight(float h){height=h;}float Cylinder::getHeight() const {return height;}float Cylinder::area() const{return 2*Circle::area()+2*3.14159*radius*height;}float Cylinder::volume() const {return Circle::area()*height;}ostream &operator<cout<<int main() {Cylinder cy1(3.5,6.4,5.2,10);cout<感谢您的阅读,祝您生活愉快。

8.3 多态性与虚函数

8.3 多态性与虚函数

例:使用虚函数 #include<iostream.h> const double PI=3.14159; class point{ double x, y; public: point(float i=0, float j=0) { x=i; y=j; } virtual double area( ) { return 0.0;} }; class circle:public point { double radius; public: circle(double r=0) { radius=r; } double area( ) { return PI*radius*radius; } };
结果分析: point *pp; pp=&c; cout<<"now the area is: "<<pp->area( )<<endl; this指针是指向当前对象的指针,在point类中area( ) 可用this指针改写为如下等同形式: double area( ){return this->x * this->y;} 在执行pp->area( )时,由于此时指针pp是基类point的 指针,this指针是指向基类的,所以pp->area( )实际调用 的是基类的成员函数area( ),而不是派生类中的成员函数 area( );
可以把纯虚函数归结为:抽象类的唯一用途是为派生类提 供基类,纯虚函数的作用是作为派生类中的成员函数的基础, 并实现动态多态性。
#include<iostream.h> class A{ protected: int x; public: A( ){x=1000;} virtual void print( ) = 0; }; class B:public A{ int y; public: B( ){y=2000;} void print( ){cout<<"y="<<y<<endl;} };

C++ 8多态与虚函数

C++ 8多态与虚函数
调用自身,无穷递归
fun(i);
8.6.1 虚函数的定义
【例8.5_1】根据赋值兼容规则可以用基类的指针指向 派生类对象,如果由该指针撤销派生类对象,则必须将析构函 数说明为虚函数,实现多态性,自动调用派生类析构函数。 通常要求将类设计成通用的,无论其他程序员怎样调用都 必须保证不出错,所以必须把析构函数定义为虚函数。 下面把【例8.5】析构函数改造为虚函数 class Person{ //数据成员略 public: virtual ~Person(); //只需在此声明一次,派生类的析构函数全为虚函数 }; //其他成员函数略
8.6.1 虚函数的定义
成员函数设置为虚函数的要点:
1. 派生类中定义虚函数必须与基类中的虚函数同名外,还必须 同参数表,同返回类型。否则被认为是重载,而不是虚函数。 如基类中返回基类指针,派生类中返回派生类指针是允许的, 这是一个例外。 静态类型:在编译时可知的引用类型或指针类型 2. 只有类的成员函数才能说明为虚函数。这是因为虚函数仅适 class Base; Base *p; //指针p的静态类型为Base 用于有继承关系的类对象。 动态类型:指针或引用所绑定的对象类型,仅运行时可知 3. 静态成员函数,是所有同一类对象共有,不受限于某个对象, class Derived:public Base; 不能作为虚函数。 Derived d; Base *p=&d; //指针p的动态类型为Derived 4. 一个类对象的静态和动态构造是相同的,实现动态多态性时, 必须使用基类类型的指针变量或引用,使该指针指向该基类的 不同派生类的对象,并通过该指针指向虚函数,才能实现动态 的多态性。
编译时的多态性 在C++ 中有两 种多态 性 运行时的 多态性

虚函数与多态性

虚函数与多态性

!=
<=
>=
&& ||
++
--
->* ‘
->
[]
()
new delete new[] delete[]
不能重载的算符
.
::
.*
?:
sizeof
8.1 运算符重载
8.1.1 重载运算符的限制
重载运算符函数可以对运算符作出新的解释,但原有基本语义不变: 不改变运算符的优先级 不改变运算符的结合性 不改变运算符所需要的操作数 不能创建新的运算符
第8章 虚函数与多态性
8.0 函数重载 8.1 运算符重载 8.2 类指针的关系 8.3 虚函数与动态联编 8.4 纯虚函数与抽象类 8.5 虚函数和多态性的应用 小结
多态性(Polymorphism)是指一个名字,多种语义;或界面 相同,多种实现。
重载函数是多态性的一种简单形式。 虚函数允许函数调用与函数体的联系在运行时才进行,称为
8.0 函数重载
重载示例:
参数个数相同 参数类型不同
# include <iostream.h> int abs ( int a ) ; double abs ( double f ) ; void main () { cout << abs ( -5 ) << endl ;
cout << abs ( -7.8 ) << endl ; } int abs ( int a ) { return a < 0 ? -a : a ; } double abs ( double f ) { return f < 0 ? -f : f ; }

第八章 多态性和虚函数

第八章  多态性和虚函数

第八章多态性和虚函数一、静态联编和动态联编1. 联编是指一个计算机程序自身彼此关联的过程.按照联编所进行阶段的不同,可分为静态联编和动态联编。

2. 静态联编是指工作在编译连接阶段,这种联编又称为早期联编,因为这种联编过程在程序开始前完成.在编译时所进行的这种联编也称静态约束,它在编译时就解决了程序中的操作调用与执行该操作代码间的关系。

3. 静态联编的程序在编译阶段并不知道将要调用的函数,只有在程序执行时才能确定要调用的函数。

例1: class Point{ int x,y; public: Point(int x1,int y1){ x=x1;y=y1; }int area() const{ return 0; } };class Rect:public Point{ int l,w; public:Rect(int x1,int y1,int l1,int w1):Point(x1,y1){ l=l1;w=w1;}int area() const{ return l*w; } };void fun(Point &p){ cout<<p.area()<<endl; }void main(){ Rect rec(2,4,10,6); fun(rec); }执行结果:0在fun()函数中,p所引用的对象执行的area()操作被关联到Point::area()的定义代码上,即始终调用Point类的area()成员函数,这是静态联编的结果。

我们期望的是p所引用的对象执行的area()操作束定到Rect类的area()函数上,这是静态联编办不到的。

4. 为了确切知道将要调用的函数,要求联编工作要在程序运行时进行.在程序运行时进行的联编工作叫动态联编、或晚期联编,实际是进行动态标识。

5. 静态联编和动态联编属于多态性,它们是在不同阶段对不同实现进行的不同选择。

上例实际是对fun()函数参数的多态性的选择,该函数的参数是一个类的对象的引用。

c++实验虚函数与多态性

c++实验虚函数与多态性

实验九:虚函数与多态性一.实验目的1.掌握动态联编的概念;2.掌握虚函数和纯虚函数的使用方法;3.掌握抽象类的使用。

二.实验内容设计一个计算图形面积的类库。

它的顶层是一个抽象类,并且提供相应的接口函数。

抽象基类Shape,派生出Point类、矩形Rectangle、正方形Square,Point类派生出圆形Circle。

要求:1、每个类有构造函数、析构函数,并有相应的输出语句,如:“正在构造圆形”2、能显示每个类的信息,如:输出“我是圆形”3、能计算面积、周长4、定义一个基类Shape类型的指针,实现动态多态5、动态创建一个圆形对象,赋值给基类Shape类型的指针变量,程序最后delete该指针,保证析构函数的正确调用(提示:虚析构函数)6、在主函数测试。

三.实验操作步骤1.输入源程序,编译、连接直到没有错误2.根据实验步骤,撰写实验报告四、实验要求1.复习教材中和实验相关的内容,提前编好程序。

2.整理上机结果,完成实验报告。

3.注意总结上机体会。

C++程序设计及实训198 #include <iostream>using namespace std;#include<string>class Shape{public:virtual float area()=0;virtual float longth()=0;virtual void show()=0;virtual ~Shape(){}};class Point:public Shape{protected:int x;int y;public:Point(int a=0,int b=0){x=a;y=b;cout<<"is constructing Point"<<endl;}void show(){cout<<"I am point"<<endl;}~Point(){cout<<"is destructing Point"<<endl;}float area(){return 0;}float longth(){实训2:简单C++程序设计return 0;}};class Rectangle:public Point{protected:int l;int w;public:Rectangle(int a=1,int b=1){l=a;w=b;cout<<"is constructing Rectangle"<<endl;}void show(){cout<<"I am Rectangle"<<endl;}float area(){return l*w;}float longth(){return 2*(l+w);}~Rectangle(){cout<<"is destructing Rectangle"<<endl;}};class Square:public Shape{protected:int r;public:Square(int a=1)199C++程序设计及实训200{r=a;cout<<"is constructing Square"<<endl;}void show(){cout<<"I am Square"<<endl;}float area(){return r*r;}float longth(){return 4*r;}~Square(){cout<<"is destructing Square"<<endl;}};class Circle:public Point{protected:int r;public:Circle(int a=1){r=a;cout<<"is constructing Circle"<<endl;}void show(){cout<<"I am Circle"<<endl;}float area(){return r*r*3.14;实训2:简单C++程序设计}float longth(){return 2*3.14*r;}~Circle(){cout<<"is destructing Circle"<<endl;}};int main(){Point a(1,1);Square b(2);Rectangle c(2,1);Shape *p=new Circle ;p->show();delete p;return 0;}{201。

第8章虚函数与多态性

第8章虚函数与多态性

2 虚函数
• 函数调用绑定 • 虚函数 • 虚函数的相关规则 • 实现多态性的步骤 • 动态绑定的实现
virtual void salary(){ } //基类中声明的虚函数 }; //下面的派生类中重写salary()都是虚函数
3 抽象类
class manager : public employee{
代码中类层次如下图所示
1 向上类型转换 2 虚函数 3 抽象类 4 RTTI 5 类层次设计的例子 6 小结
employeeCtrl payroll()
manager salary()
employee salary()
向上类型转换
programmer salary()
parttime salary()
void salary(){ /*程序员工资的计算和发放*/
} };
3 抽象类
class parttime : public employee{
4 RTTI
public: void salary(){
5 类层次设计的例子
/*兼职人员工资的计算和发放*/
6 小结
}
};
上面的代码可以修改为如下形式
1 向上类型转换
派生类向上转换为基类类型,这在逻辑上是 合理的,在物理上也是安全的。
▪ 在逻辑上方面,派生类继承基类的公共接口,能 够发送给基类对象的消息也能够发送给派生类对 象。派生类是特殊的基类类型,派生类对象(或 地址)可以作为基类的实例(或地址),替代基 类对象(或地址)使用。
▪ 在物理方面,基类的成员被派生类继承,在派生 类对象中封装着一个无名的基类子对象,派生类 对象的存储空间中从首地址开始存放的的这个基 类子对象。因此,进行向上类型转换时,通过派 生类对象切片,能够提供足够的基类信息,得到 基类对象。而使用基类指针(或引用)指向派生 类对象时也不会破坏指针(或引用)的指向规则。

第八讲 多态性和虚函数

第八讲 多态性和虚函数


实现机制
– 将指定的运算表达式转化为对运算符函数的调 用,运算对象转化为运算符函数的实参。 – 编译系统对重载运算符的选择,遵循函数重载 的选择原则。
8
C++语言程序设计
规则和限制
运算符重载
C++不允许重载下列四个运算符: . .* :: ?: 只能重载C++语言中已有的运算符, 不可臆造新的。 不改变原运算符的优先级和结合性。 不能改变操作数个数。 经重载的运算符,其操作数中至少应 该有一个是自定义类型。
22
//后置单目运算符重载 Clock Clock::operator ++ (int) { //注意形参表中的整型参数 Clock old = *this; ++(*this); //调用前置“++”运算符 return old; }
23
程序运行结果为: First time output: 23:59:59 Show myClock++: 23:59:59 Show ++myClock: 0:0:1

– 消息:对类的成员函数的调用 – 不同的行为:不同的实现,即调用了不 同的函数
3
C++语言程序设计
多态的类型
多态性概述

强制多态:数据类型转换(隐式或显 式)

重载多态:函数重载,运算符重载 包含多态:虚函数 类型参数化多态:函数模板,类模板
4
C++语言程序设计
多态的实现
多态性概述

14
Complex Complex::operator + (const Complex &c2) const { //重载运算符函数实现 return Complex(real + c2.real, imag + c2.imag); //创建一个临时无名对象作为返回值 } Complex Complex::operator - (const Complex &c2) const { //重载运算符函数实现 return Complex(real - c2.real, imag c2.imag); //创建一个临时无名对象作为返回值 }
  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);
相关文档
最新文档