chapter9 多态性和虚函数1(12[1].16)

合集下载

多态和虚函数

多态和虚函数

多态和虚函数
多态和虚函数是面向对象编程中非常重要的概念。

多态是指同一种操作作用于不同的对象上面,可以产生不同的执行结果。

而虚函数则是实现多态的一种方式。

在面向对象编程中,我们经常会遇到需要对不同的对象进行相同的操作的情况。

例如,我们可能需要对不同的动物进行喂食,但是不同的动物需要不同的食物。

这时候,我们就可以使用多态来实现这个功能。

我们可以定义一个抽象的动物类,然后让不同的动物类继承这个抽象类,并实现自己的喂食方法。

然后我们就可以通过调用这个抽象类的喂食方法来喂食不同的动物,而不需要知道具体是哪种动物。

虚函数是实现多态的一种方式。

虚函数是在基类中定义的一种特殊的函数,它可以被子类重写。

当我们通过基类指针或引用调用虚函数时,实际上会调用子类中重写的虚函数。

这样就可以实现多态,让不同的子类实现自己的方法,而不需要知道具体是哪种子类。

虚函数的实现是通过虚函数表来实现的。

每个对象都有一个指向虚函数表的指针,虚函数表中存储了虚函数的地址。

当我们调用虚函数时,实际上是通过对象的指针或引用找到虚函数表,然后根据虚函数的索引找到对应的虚函数地址,最终调用虚函数。

多态和虚函数是面向对象编程中非常重要的概念。

通过使用多态和
虚函数,我们可以实现代码的复用和扩展性,让代码更加灵活和易于维护。

虚函数和多态性

虚函数和多态性

虚函数和多态性一、多态性的含义多态性是指通过(基类)指针或(基类)引用调用函数,这种调用是动态解析的,即在编译期间确定调用哪个函数。

因为派生类对象包含一个完整的基类对象,换句话说,每个派生类对象也是一个基类对象。

因此,可以用基类指针来存储派生类对象的地址。

但是,反之就不行。

不能用派生类的指针来存储基类对象的地址,因为每个基类对象只表示派生类的一部分。

从上图的派生关系,可以定义一个类Box的指针,来存储每个派生类的地址(包括多重派生类的地址)。

例如:CerealPack breakfast;Box* pBox=&breakfast;Carton* pCarton=&breakfast;Contents* pContents=&breakfast;这三个语句都是正确的,因为类Box是类CerealPack的间接基类,类Carton和类Content 是它的直接基类。

二、指针的静态类型和动态类型对于一个基类指针或引用,定义时的类型称为它的“静态类型”,实际指向对象时的类型称为“动态类型”。

在任意时刻,指针pBox都可以包含任何以Box为基类的派生类对象的地址。

该指针在声明时的类型是“Box*”,因此它的静态类型是“Box*”。

同时,它还具有动态类型。

当pBox 指向Carton对象时,其动态类型是“Carton*”。

当pBox指向ToughPack对象时,其动态类型是“ToughPack*”。

在pBox指向Box对象时,其动态类型和静态类型相同,是“Box*”类型。

编译器根据基类指针的动态类型来调用合适的虚函数版本,这个就是多态性最重要的内容。

三、多态类的含义当一个类至少包含一个虚函数时,称这个类具有多态性,或说这个类是多态类。

获得多态性有两种方式:从基类继承虚函数和自定义一个虚函数。

通过这两种方式,都可以获得多态性。

四、静态绑定和动态绑定㈠静态绑定和动态绑定的定义静态绑定又叫静态解析、静态调用,是指在源程序中确定的调用关系。

C++面向对象程序设计 多态性与虚函数

C++面向对象程序设计 多态性与虚函数
一个函数名与其实现的代码联系在一起,即主调函数代码 必须与被调函数代码连接起来。
按照联编所在的阶段,联编分为静态联编(static binding) 和动态联编(dynamic binding)。 静态联编又称先期联编(early binding),是在编译时进行的, 即是在编译阶段就必须确定函数名与代码间的对应关系。 换句话说,主调函数和被调代码的关系早在编译时就确定 了。
的内容实现多态性。但是,如果基类中的没有将函数print()定
义为虚函数,那么,即使在类层次中该函数被重载(函数名字
和参数表完全相同),仍然不可能实现任何多态性。在这种场Student类
合,联编还是静态的。
print()
docin/sundae_meng
Smallstudent类
蚌埠学院计算机系 pr7int()
⑴函数重载实现多态:对同一个函数名,当用不同的实参调用时,会
调用到不同的重载函数版本,因而完成不同的功能,这是一种多态性 的体现。
⑵模板实现多态:模板是一类函数或类的样板,通过用不同的模板实
参调用模板,同一个名字可生成不同的具体函数或具体类,从而实现 不同的功能,这也是一种多态性的体现。
⑶虚函数实现多态:通过动态束定机制,使相同的函数调用代码可能
C++面向对象程序设计
第九章 多态性与虚函数
docin/sundae_meng
1
C++面向对象程序设计
学习目标
⑴理解多态性和虚函数的概念 ⑵了解静态多态性和动态多态性 ⑶掌握虚函数的定义和调用方法 ⑷掌握多态性的实现方法以及虚函数在其实现中起
到的作用 ⑸掌握纯虚函数和抽象类的概念及应用
docin/sundae_meng

c++ 第9章 多态性与虚函数

c++ 第9章  多态性与虚函数

程序运行结果为:
Draw a Shape. The color is Red
Draw a Line from (10, 10) to (100, 100) , with color Green Draw a Circle at center (50, 50) with radius 20 and color Black
例9.1 (续二)
class CLine:public CShape { private: CPoint Start; CPoint End; public: CLine(CPoint s, CPoint e, char *c):CShape(c),Start(s),End(e) {} virtual void Draw() { cout << "Draw a Line from (" << Start.GetX() << "," << Start.GetY(); cout << ") to ("<< End.GetX() << "," << End.GetY() << "), with color "; PrintColor(); } };
Draw a Shape. The color is Green Draw a Shape. The color is Red Black
例9.1 用虚函数实现动态多态
#include <iostream.h> #include <string.h> class CPoint { private: int X; int Y; public: CPoint(int x=0, int y=0) { X=x; Y=y; } CPoint(CPoint &p) { X=p.X; Y=p.Y; } int GetX() { return X; } int GetY() { return Y; } };

多态性与虚函数.doc

多态性与虚函数.doc

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

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

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

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

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

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

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

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

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

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

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

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

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

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

它又称运行时的多态性。

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

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

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

程序设计基础第9讲多态性与虚函数

程序设计基础第9讲多态性与虚函数

void Clock::operator ++(int) //后置单目运算符重载 { Second++; if(Second>=60) { Second=Second-60; Minute++; if(Minute>=60){Minute=Minute-60;Hour++;Hour=Hour%24;} } cout<<"Clock++: "; } void main() { Clock myClock(23,59,59); cout<<"First time output:"; myClock.ShowTime(); myClock++; myClock.ShowTime(); ++myClock; myClock.ShowTime(); }
案例9.5 虚函数的应用。
#include <iostream.h> class Mammal //类的声明及其实现 { public: Mammal(){ cout<<"Mammal constructor called."<<endl; } virtual ~Mammal() //用virtual声明虚函数 {cout<<"Mammal destructor called."<<endl;}//虚函数在基类中的实现 virtual void Speak() { cout<<"Mammal speak."<<endl; } }; class Dog:public Mammal //公有派生类Mammal { public: Dog(){ cout<<"Dog constructor called."<<endl; } ~Dog(){ cout<<"Dog destructor called."<<endl; } void Speak() { cout<<"Woof!"<<endl; } //派生类中虚函数的实现 }; void main() { Mammal *p=new Dog; p->Speak(); delete p; }

多态性和虚函数


成员函数形式: 返回类型 operator 重载运算符(入口参数表); 友元函数形式: friend 返回类型 operator 重载运算符(入口参数 表);
重载方式示例 class A { A operator +(A&); friend A operator +(A&, A&); };
用成员函数重载运算符: 一般而言,重载一元运算符没有参数;重载 二元运算符只有一个参数。 一般基于某个对象调用成员函数,这个对象 是一个隐含的操作数,就是被调用的运算符函数的 一个操作数,而且是第一操作数 有了运算符重载以后,当程序中出现表达式: “ a = b + c;”的时候编译程序将其解释为: “a = b.operator+( c )";
“绑定”——就是让函数调用与函数体产生 关联。 在编译时就确定——叫“早期绑定”; 在程序运行时才确定——叫“晚期绑定”。 而C++的多态性在“早期绑定”和“晚期绑 定”两方面都有体现。
2 虚函数
虚函数是在基类中使用了关键字virtual 的成员函数。 虚函数与函数重载的区别: 1、虚函数定义在基类和派生类中,函 数原型完全一致; 2、函数重载在同一个类中,或者都在 类外定义,函数原型必定不完全相同。
用友元函数重载运算符: 不是成员函数,也没有this指针,用友元函 数重载二元运算符(双目运算符)时,要有两个参 数;重载一元运算符(单目运算符)时,要有一个 参数。 当程序中出现表达式:“ a = b + c;”的时候 编译程序将其解释为: “a = operator+(b,c )";
单目运算符重载: 一般来讲,单目运算符最好重载为成员函数, 而双目运算符则最好重载为友元函数。 可以重载为没有参数的成员函数或者带有一 个参数的非成员函数(友元函数),其参数必须 是用户定义类型的对象或者是对该对象的引用。

【大学】C++面向对象程序设计 多态性与虚函数


调用不同的类(基类或派生类)的虚函数,从而完成不同的功能,这
又是一种多态性的体现。
.
蚌埠学院计算机系 4
C++面向对象程序设计
9.1.2 静态多态性和动态多态性
编译时多态通过静态联编实现,运行时多态通过动态联 编实现。
1 联编 在面向对象程序设计中,联编(binding)的含义是把
一个函数名与其实现的代码联系在一起,即主调函数代码 必须与被调函数代码连接起来。
.
蚌埠学院计算机系 12
C++面向对象程序设计
9.2 对虚函数的限制
9.2.1 声明虚函数的限制
一般情况下,可将类中具有共性的成员函数声明为虚函数,而个 性的函数往往为某一个类独有,声明为一般成员函数。将类的成员函 数声明为虚函数有利于编程,但下面的函数不能声明为虚函数:
⑴构造函数不能声明为虚函数。构造函数在对象创建时调用,完成对象 的初始化,此时对象正在创建中,基类指针无从指向。只有在构造过 程完成后,对象才存在,才能被基类指针指向。
9.1.1 多态性的实现方法
同一段代码,当用不同的对象去调用时,该代码具有不同的功能,这 称为多态性。C++提供的多态性分为静态多态性(编译时多态)和动 态多态性(运行时多态)。静态多态性是一种编译时的多态,是通过 重载和模板实现的。动态多态性是一种运行时的多态,其基础是数据 封装和继承机制,通过继承建立类层次,并通过在基类中定义虚函数 来实现多态性,即在基类和派生类中建立同名的函数,但是函数的功 能是不同的。
2 静态多态性
在没有类层次的场合,使用函数重载的方式实现静态多态性。 各个重载函数名称相同,但参数表应在参数个数、类型和次序 上有所不同。编译器根据参数表来识别各个重载函数。根据参 数表,系统在编译时就完成静态联编的过程。关于没有类层次 的函数重载实现多态的例子前面已经介绍,这里不再赘述。

最新《C++程序设计案例教程》教学参考第9章 多态性和虚函数

第9章多态性和虚函数
一、教学要求
熟练掌握:C++中多态性的内容、抽象类的定义和使用。

掌握:派生类对象调用基类函数和派生类同名函数、虚函数的使用,基类指针调用派生类同名函数、纯虚函数的定义和作用、抽象类的定义和作用。

了解:以上各种情况下,析构函数被调用情况。

二、教学重点
C++中多态性的内容、抽象类的定义和使用、使用虚函数与抽象类的区别。

三、教学难点
虚函数的定义、使用和作用。

四、课时安排
本章安排4课时。

其中,理论讲授2课时。

五、教学大纲
9.1多态性和虚函数
9.1.1 多态性
9.1.2 虚函数的使用
9.2纯虚函数和抽象类
六、主要概念
1.C++面向对象程序的多态性内容
2.虚函数的定义和作用
3. 纯虚函数的概念
4. 抽象类的定义和作用。

《C++程序设计案例教程》第九章多态性和虚函数课件

目录
知识讲解
如果一个类中包含了纯虚函数,则这个类就称为抽象类。纯虚 函数的定义方式如下:
virtual 函数类型 函数名(参数表)=0; 纯虚函数没有函数体。因为纯虚函数不能被调用,所以包含纯 虚函数的不能建立对象。抽象类的作用只是作为一组派生类的基类, 提供公共接口。 虽然抽象类不能定义对象,但可以定义指针变量,将派生类的 地址赋给指针变量,实现用统一的方式调用派生类中的虚函数。 需要注意的是,如果派生类没有重写抽象类中的纯虚函数,那 么纯虚函数被派生类继承后,仍然是纯虚函数,这样只能留给间接 派生类重新定义,抽象类的直接派生类也成为抽象类,也不能建立 对象。
r.Graph::display(); 当然,可以使用指针变量代替对象名调用函数。如果使用指 针变量,可以随时将执行对象的地址赋给指针。这样一来,无 论对象是什么,代码都可以统一采用p->display()的形式。
目录
知识讲解
在继承的机制中,派生类新增的成员函数很可 能与继承得来的基类的成员函数同名,并且参数 个数和参数类型也相同,因此,这种现象不属于 函数重载。如果用派生类对象调用同名的成员函 数,派生类会屏蔽继承的基类的成员函数,执行 自己新增的成员函数。如果要用派生类对象调用 继承的基类同名函数,需要在函数前增加基类名。
A纯dd虚yo函ur数te的xt i使n h用ere
建立纯虚函数,实现虚函数在派生类中的模板作用。
目录
9.2 纯虚函数和抽象类
源代码展示
#include <iostream>
using namespace std;
class Graph
{
public:
virtual void display()=0;
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

class Complex {private: double r; double i; public:
//复数类声明 复数类声明
d3=d1.operator +(d2);
//复数实部 复数实部 //复数虚部 复数虚部
d3=operator +(d1,d2);
d3=Complex(1,1); Complex(double a=0,double b=0){r=a; i=b;} d3=d1.Add(d2);
2. 替代后派生类对象可以作为基类对象使用
,但只能使用从基类继承的成员。 但只能使用从基类继承的成员。
中国传媒大学版权所有
多态性 本章主要内容
1. 多态性 2. 运算符重载 运算符重载(overload) 3. 虚函数 虚函数(virtual) 4. 纯虚函数和抽象类
中国传媒大学版权所有
多态性 基本概念
中国传媒大学版权所有 16
5.单目运算符前置++ 5.单目运算符前置++ 单目运算符前置
类的成员函数(无形参) 重载为 Complex 类的成员函数(无形参)

经重载后, 经重载后,++a 相当于 a.operator ++( ); 类的友员函数(Complex形参 形参) 重载为 Complex 类的友员函数(Complex形参)
d3=d1+d2;
函数调用形式) 或 ( 函数调用形式 d3=? 成员函数或友元2选1 成员函数或友元 选
中国传媒大学版权所有
双目运算符2.operator= 双目运算符2.operator= 成员函数形式
//赋值运算符缺省重载 且只能重载为成员函数 赋值运算符缺省重载,且只能重载为成员函数 赋值运算符缺省重载 Complex &Complex ::operator =(const Complex &c) { r=c.r; i=c.i; return *this;//返回当前对象 只能重载为成员函数) 返回当前对象(只能重载为成员函数 返回当前对象 只能重载为成员函数) //熟悉引用返回的应用场合,掌握相关操作 熟悉引用返回的应用场合, 熟悉引用返回的应用场合 //d1=d2; (d1=d2).SetComplex(1,2); d1=d2=d3; //d1.operator=(d2.operator=(d3));//右结合性不变 右结合性不变
5.
思路: 思路:
根据运算符语义, 根据运算符语义,分析函数所需传入的数据及需要返回的 数据, 数据,确定函数参数及返回类型 中国传媒大学版权所有
函数参数类型选择
1. 2. 3. 4. 5. 6. 7. 8.
void Test(Complex c, Complex &r ,Complex *p) { c.SetComplex(0,0); r.SetComplex(0,0); p->SetComplex(0,0); } void main(){ Complex s(1,2),t(1,2),g(1,2); Test(s,t,&g); }
3.
函数实现
中国传媒大学版权所有
双目运算符1.operator+ 双目运算符1.operator+ 成员函数形式(对象作参数) 成员函数形式(对象作参数) //返回和对象 d3=d1+d2; d4=d1+d2+d3; 返回和对象 Complex Complex::operator +(Complex c) { Complex sum; sum.r=r+c.r; sum.i=i+c.i; return sum; ; //return Complex(r+c.r,i+c.i); }
中国传媒大学版权所有
双目运算符3.operator+= 双目运算符3.operator+= 成员函数形式
//赋值类运算符都必须重载为成员函数形式 //赋值类运算符都必须重载为成员函数形式 //原因:要返回* //原因:要返回*this 原因
Complex &Complex ::operator +=(const Complex& c) { r+=c.r; i+=c.i; return *this; ; }
C++程序设计 程序设计
第九章 多态性与虚函数
马海燕 sea2002@
继承与派生 --赋值兼容原则 --赋值兼容原则
1. 在任何需要基类对象的地方都可以用派生
类对象替代,三种场合如下: 类对象替代,三种场合如下:
派生类的对象可以赋值给基类对象; 派生类的对象可以赋值给基类对象; 派生类对象可以初始化基类的引用; 派生类对象可以初始化基类的引用; 派生类对象的地址可以给基类指针赋值; 派生类对象的地址可以给基类指针赋值;

经重载后, 经重载后, ++a 相当于 operator ++(a); 函数头设计: 函数头设计:
– –
语义分析: 语义分析:Complex
a(1,2),b; b=++a; ++(++a);<---无法实现 a(1,2),b; b=++a;无++(++a);<--无法实现
即使返回临时对象,也依然可以作++(++a)的操作, 即使返回临时对象,也依然可以作++(++a)的操作,因为临时对象也是对象 ++(++a)的操作 ,跟基本数据类型不一样。对象可以调用成员函数。从语义上来讲,我们重 跟基本数据类型不一样。对象可以调用成员函数。从语义上来讲, 载的++无法与原++完全一致,但尽可能接近。 不能避免++(++a)出现, ++(++a)出现 载的++无法与原++完全一致,但尽可能接近。 不能避免++(++a)出现,但该 ++无法与原++完全一致 表达式中不需要对操作数a进行累加修改,所以选对象作返回值。 表达式中不需要对操作数a进行累加修改,所以选对象作返回值。 参数:需要对传入对象进行修改,友元形式必须选Complex 参数:需要对传入对象进行修改,友元形式必须选Complex & 返回值:返回临时对象,且值同自增后对象 返回值:返回临时对象,
中国传媒大学版权所有
函数返回值类型选择
1. 2. 3. 4. 5. 6. 7.
void Test(Complex c, Complex &r ,Complex *p); Complex Test(Complex &r){ return r; }返回临时对象 返回临时对象 Complex &Test(Complex &r,int a)//返回非临时对象 返回非临时对象 {return r;} Complex *Test(Complex &r,int a,int b)//返回非临时对象地址 返回非临时对象地址 {return &r;}
运算符重载函数设计
1.
重载形式选择
成员函数 友元函数
2.
函数头设计(根据语义确定参数及返回值类型) 函数头设计(根据语义确定参数及返回值类型)
… operator+(…) … operator=(…) … operator>(…) … operator++(…) … operator++(…,int)
1. 多态性是面向对象程序设计的重要特征之一 多态性就是多种表现形式,具体来说,可以用“ 多态性就是多种表现形式,具体来说,可以用“一 个对外接口,多个内在实现方法”表示。 个对外接口,多个内在实现方法”表示。 2. 多态的实现形式 – 静态联编(编译阶段确定函数调用) 静态联编(编译阶段确定函数调用)
Complex d1(1.0,2.0),d2(2.0,3.0),d3,d4; 要求设计程序实现d1,d2相加,d3保存和值 相加, 保存和值 保存和值. 要求设计程序实现 相加
中国传媒大学版权所有 5
静态多态 运算符重载
1. 2. 3. 4.
针对Complex这种新数据类型 为运算符赋予新的含义。 针对 这种新数据类型,为运算符赋予新的含义。 这种新数据类型 为运算符赋予新的含义 运算符重载实质: 函数重载(以参与运算的数据类型为参数 运算符重载实质 函数重载 以参与运算的数据类型为参数 进行区分). 进行区分 如 d3=d1+d2; 相当于 d3=d1. operator+ (d2); 函数名: 函数名:operator 运算符 两种重载形式(选择其一) 两种重载形式(选择其一) 成员函数 参数:一般为运算符所需操作数减 函数(参数 一般为运算符所需操作数减1个 成员函数 参数 一般为运算符所需操作数减 个)
中国传媒大学版权所有 15
4.双目运算符关系大于> 4.双目运算符关系大于> 双目运算符关系大于
//if(d1>d2){…}//假设:根据实部大小确定复数大小 假设: 假设 bool Complex ::operator >(const Complex &c) { return r>c.r?true:false; }// 重载为友员函数? 重载为友员函数?
d3=d1+d2; 或 d3=d1.operator+(d2); 中国传媒大学版权所有
10
双目运算符1.operator+ 双目运算符1.operator+ 成员函数形式(常引用作参数) 成员函数形式(常引用作参数)
相关文档
最新文档