第-8-章(2)━━多态性与虚函数课件.ppt
《第-8-章(2)━━多态性与虚函数课件.ppt》由会员分享,可在线阅读,更多相关《第-8-章(2)━━多态性与虚函数课件.ppt(36页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、C+程序设计程序设计第第8章章(2)多态性与虚函数多态性与虚函数1主要内容主要内容lC+的多态性的多态性l动态多态性的实现条件动态多态性的实现条件l虚函数的声明虚函数的声明l虚函数的特性与调用虚函数的特性与调用l静态关联、动态关联静态关联、动态关联l虚析构函数虚析构函数l纯虚函数纯虚函数l抽象类抽象类l综合实例综合实例2C+的多态性的多态性l多态性:多态性:指对不同类型的对象发送同样的消息(即调用同名的函数),不同类型的指对不同类型的对象发送同样的消息(即调用同名的函数),不同类型的对象在接收时会产生不同的行为(即执行各自同名的函数)。对象在接收时会产生不同的行为(即执行各自同名的函数)。l编
2、译时多态性(静态多态性):编译时多态性(静态多态性):指在编译阶段,系统就可根据所操作的对象,确定指在编译阶段,系统就可根据所操作的对象,确定其具体的操作。其具体的操作。编译时多态性是通过函数重载、运算符重载来实现的。编译时多态性是通过函数重载、运算符重载来实现的。函数重载是函数重载是根据函数调用式中所给出的实参的类型或实参的个数,在编译阶段系统就可确定调根据函数调用式中所给出的实参的类型或实参的个数,在编译阶段系统就可确定调用的是同名函数中的哪一个。运算符重载是根据运算式中所给出的运算对象的类型,用的是同名函数中的哪一个。运算符重载是根据运算式中所给出的运算对象的类型,在编译阶段系统就可确定
3、执行的是同种运算中的哪一个。在编译阶段系统就可确定执行的是同种运算中的哪一个。l运行时多态性(动态多态性):运行时多态性(动态多态性):指在编译阶段,系统仅根据函数调用式是无法确定指在编译阶段,系统仅根据函数调用式是无法确定调用的是同名函数中的哪一个;必须在程序运行过程中,动态确定所要调用函数的调用的是同名函数中的哪一个;必须在程序运行过程中,动态确定所要调用函数的当前对象,并根据当前对象的类型来确定调用的是同名函数中的哪一个。当前对象,并根据当前对象的类型来确定调用的是同名函数中的哪一个。运行时多运行时多态性是通过态性是通过“类的继承关系类的继承关系”加上加上“虚函数虚函数”联合起来实现的。
4、联合起来实现的。3动态多态性的实现条件动态多态性的实现条件l要有类的继承层次结构:要有类的继承层次结构:一个基类可以派生出不同的派生类,各派生类中可以新增一个基类可以派生出不同的派生类,各派生类中可以新增与基类中的函数名字相同、参数个数及类型也相同的成员,这些同名的成员函数在与基类中的函数名字相同、参数个数及类型也相同的成员,这些同名的成员函数在不同的派生类中就有不同的含义!这样,不同的派生类中就有不同的含义!这样,在类的继承结构中,不同的层次上出现了在类的继承结构中,不同的层次上出现了名字相同、参数个数及类型也相同、但功能不同的函数!名字相同、参数个数及类型也相同、但功能不同的函数!l引入虚
5、函数:引入虚函数:作用是在由一个基类派生出的类体系中实现作用是在由一个基类派生出的类体系中实现“一个接口,多种方法一个接口,多种方法”,主要用于建立通用程序。对于同一类体系中的各层次派生类,使用虚函数可实现,主要用于建立通用程序。对于同一类体系中的各层次派生类,使用虚函数可实现统一的类接口,以便用相同的方式对各层次派生类的对象进行操作。统一的类接口,以便用相同的方式对各层次派生类的对象进行操作。虚函数是基类虚函数是基类的成员函数,是为了实现某一种功能而假设的虚拟函数,在该基类的各层次派生类的成员函数,是为了实现某一种功能而假设的虚拟函数,在该基类的各层次派生类中对该虚函数可有各自不同的定义中对
6、该虚函数可有各自不同的定义!l要能体现虚函数的特性:要能体现虚函数的特性:必须通过基类的对象指针、基类的对象引用来调用各层次必须通过基类的对象指针、基类的对象引用来调用各层次派生类对象的同名虚函数,才能体现虚函数的特性!派生类对象的同名虚函数,才能体现虚函数的特性!因为只有这样才能用相同的调因为只有这样才能用相同的调用方式去调用不同层次派生类对象的同名虚函数,从而实现动态多态性。用方式去调用不同层次派生类对象的同名虚函数,从而实现动态多态性。4虚函数的声明虚函数的声明l虚函数的声明:虚函数的声明:class 基类基类 virtual 返回值类型返回值类型 成员函数名成员函数名 (形参表形参表)
7、函数体函数体 ;当一个基类的某成员函数声明为虚函数,则在该基类的所有派生类中,与虚函数同名、当一个基类的某成员函数声明为虚函数,则在该基类的所有派生类中,与虚函数同名、参数个数及类型相同、且返回值类型也相同的,不论是否有关键字参数个数及类型相同、且返回值类型也相同的,不论是否有关键字 virtual 修饰,都修饰,都是虚函数,反之不然。但要注意:若在派生类中只是与虚函数同名,而参数个数或是虚函数,反之不然。但要注意:若在派生类中只是与虚函数同名,而参数个数或类型有不同时,属于函数重载,不是虚函数!类型有不同时,属于函数重载,不是虚函数!virtual 只是用在类中声明虚函数,若在类外定义虚函数
8、前面不要加只是用在类中声明虚函数,若在类外定义虚函数前面不要加 virtual。构造函数、静态成员函数不能声明为虚函数!析构函数可以声明为虚函数。构造函数、静态成员函数不能声明为虚函数!析构函数可以声明为虚函数。5虚函数的特性与调用虚函数的特性与调用l如何体现虚函数的特性?如何体现虚函数的特性?只有通过基类的对象指针、基类的对象引用来调用派生类只有通过基类的对象指针、基类的对象引用来调用派生类对象的虚函数时,才能体现虚函数的特性!而通过派生类对象的对象名、对象指针、对象的虚函数时,才能体现虚函数的特性!而通过派生类对象的对象名、对象指针、对象引用来调用虚函数时,无法体现虚函数的特性!对象引用来
9、调用虚函数时,无法体现虚函数的特性!l派生类对象中派生类对象中一般成员函数一般成员函数的调用的调用方法:方法:可通过派生类对象的对象名、对象指针、对象引用来调用!调用过程:若派生类新可通过派生类对象的对象名、对象指针、对象引用来调用!调用过程:若派生类新增成员函数中存在该函数,则被调用;若不存在,则调用上一层基类中的该函数;增成员函数中存在该函数,则被调用;若不存在,则调用上一层基类中的该函数;若若这这一一层层基基类类中也不存在,就中也不存在,就继续继续往上一往上一层寻层寻找找 ,直至找到,直至找到该该函数并被函数并被调调用。用。l派生类对象中派生类对象中一般成员函数一般成员函数的调用的调用方
10、法:方法:可通过基类的对象指针、基类的对象引用来调用派生类对象中的一般成员函数!但可通过基类的对象指针、基类的对象引用来调用派生类对象中的一般成员函数!但只能调用派生类中从该基类继承过来的那部分成员函数!只能调用派生类中从该基类继承过来的那部分成员函数!6虚函数的特性与调用虚函数的特性与调用l派生类对象中派生类对象中虚函数虚函数的调用的调用方法:方法:派生类对象的虚函数也是成员函数,可按一般成员函数的方式调用!即:可通过派派生类对象的虚函数也是成员函数,可按一般成员函数的方式调用!即:可通过派生类对象的对象名、对象指针、对象引用来调用!调用过程与一般成员函数的调用生类对象的对象名、对象指针、对
11、象引用来调用!调用过程与一般成员函数的调用过程相同!由此可见,这种调用方式无法体现虚函数的特性!过程相同!由此可见,这种调用方式无法体现虚函数的特性!l派生类对象中派生类对象中虚函数虚函数的调用的调用方法:方法:可通过基类的对象指针、基类的对象引用来调用派生类对象的虚函数!调用过程:可通过基类的对象指针、基类的对象引用来调用派生类对象的虚函数!调用过程:调调用的是派生用的是派生类类中的虚函数!若派生中的虚函数!若派生类类中没有重新定中没有重新定义该义该虚函数,虚函数,则调则调用的是上一用的是上一层层基基类类中的中的该该虚函数;若在虚函数;若在这这一一层层基基类类中也没有重新定中也没有重新定义该
12、义该虚函数,就虚函数,就继续继续往上一往上一层寻层寻找找 ,直至,直至基类的对象指针、基类的对象引用它们本身所属的那一层基类!基类的对象指针、基类的对象引用它们本身所属的那一层基类!l动态多态性的实现:动态多态性的实现:可以让基类的对象指针(或基类的对象引用)先后指向(或先可以让基类的对象指针(或基类的对象引用)先后指向(或先后引用)同一类族中不同派生类的对象,以便用相同的调用方式去调用不同派生类后引用)同一类族中不同派生类的对象,以便用相同的调用方式去调用不同派生类对象中的同名虚函数,从而实现动态多态性。对象中的同名虚函数,从而实现动态多态性。7【例例】(派生类对象中(派生类对象中一般成员函
13、数一般成员函数的调用的调用方法:可通过派生类对象的对象名、方法:可通过派生类对象的对象名、对象指针、对象引用来调用!注意调用过程。)对象指针、对象引用来调用!注意调用过程。)#includeclass A int x;public:A(int a)x=a;void g()cout “A:x=”x endl;class B:public A int y;public:B(int a,int b):A(a)y=b;void f()cout “B:y=”y endl;class C:public B int m;public:C(int a,int b,int c):B(a,b)m=c;void g
14、()cout “C:m=”m endl;class D:public C int n;public:D(int a,int b,int c,int d):C(a,b,c)n=d;void f()cout “D:n=”n f();pd-g();D&dd1=d1;dd1.f();dd1.g();运行:运行:D:n=4C:m=3D:n=4C:m=3D:n=4C:m=3 从从A类继承的成员:类继承的成员:int x;g();不是虚函数不是虚函数从从B类继承的成员:类继承的成员:int y;f();不是虚函数不是虚函数从从C类继承的成员:类继承的成员:int m;g();不是虚函数不是虚函数D类新增的成
15、员:类新增的成员:int n;f();不是虚函数不是虚函数 pdd1对象对象 dd18【例例】(派生类对象中(派生类对象中虚函数虚函数的调用的调用方法:可通过派生类对象的对象名、对象指方法:可通过派生类对象的对象名、对象指针、对象引用来调用!注意调用过程与一般成员函数相同!由此可见,这种调用方针、对象引用来调用!注意调用过程与一般成员函数相同!由此可见,这种调用方式无法体现虚函数的特性!)式无法体现虚函数的特性!)#includeclass A int x;public:A(int a)x=a;virtual void g()cout “A:x=”x endl;class B:public A
16、 int y;public:B(int a,int b):A(a)y=b;virtual void f()cout “B:y=”y endl;class C:public B int m;public:C(int a,int b,int c):B(a,b)m=c;void g()cout “C:m=”m endl;class D:public C int n;public:D(int a,int b,int c,int d):C(a,b,c)n=d;void f()cout “D:n=”n f();pd-g();D&dd1=d1;dd1.f();dd1.g();运行:运行:D:n=4C:m=3
17、D:n=4C:m=3D:n=4C:m=3 从从A类继承的成员:类继承的成员:int x;g();虚函数虚函数从从B类继承的成员:类继承的成员:int y;f();虚函数虚函数从从C类继承的成员:类继承的成员:int m;g();虚函数虚函数D类新增的成员:类新增的成员:int n;f();虚函数虚函数 pdd1对象对象 dd19【例例】(派生类对象中(派生类对象中一般成员函数一般成员函数的调用的调用方法:可通过基类的对象指针、基类方法:可通过基类的对象指针、基类的对象引用来调用!但只能调用派生类中从该基类继承来的那部分成员函数!)的对象引用来调用!但只能调用派生类中从该基类继承来的那部分成员函
18、数!)#includeclass A int x;public:A(int a)x=a;void g()cout “A:x=”x endl;class B:public A int y;public:B(int a,int b):A(a)y=b;void g()cout “B:y=”y endl;class C:public B int z;public:C(int a,int b,int c):B(a,b)z=c;void g()cout “C:z=”z endl;void f()cout “Bye!”g();aa1.g();/pa-f();为为什么不行?什么不行?B *pb=&c1,&bb
19、1=c1;pb-g();bb1.g();/pb-f();为为什么不行?什么不行?C *pc=&c1,&cc1=c1;pc-g();cc1.g();pc-f();从从A类继承的成员:类继承的成员:int x;g();不是虚函数不是虚函数从从B类继承的成员:类继承的成员:int y;g();不是虚函数不是虚函数C类类新增的成员:新增的成员:int z;g();不是虚函数不是虚函数f();不是虚函数不是虚函数 pb pa pcC1对象对象运行:运行:A:x=1A:x=1B:y=2B:y=2C:z=3C:z=3 Bye!10【例例】(派生类对象中(派生类对象中虚函数虚函数的调用的调用方法:可通过基类的
20、对象指针、基类的对象方法:可通过基类的对象指针、基类的对象引用来调用!注意:引用来调用!注意:调调用的是派生用的是派生类类中的虚函数!若派生中的虚函数!若派生类类中没有重新定中没有重新定义该义该虚函虚函数,数,则调则调用的是上一用的是上一层层基基类类中的中的该该虚函数,虚函数,)#includeclass A int x;public:A(int a)x=a;virtual void g()cout “A:x=”x endl;class B:public A int y;public:B(int a,int b):A(a)y=b;void g()cout “B:y=”y endl;class
21、C:public B int z;public:C(int a,int b,int c):B(a,b)z=c;void g()cout “C:z=”z endl;virtual void f()cout “Bye!”g();aa1.g();/pa-f();为为什么不行?什么不行?B *pb=&c1,&bb1=c1;pb-g();bb1.g();/pb-f();为为什么不行?什么不行?C *pc=&c1,&cc1=c1;pc-g();cc1.g();pc-f();从从A类继承的成员:类继承的成员:int x;g();虚函数虚函数从从B类继承的成员:类继承的成员:int y;g();虚函数虚函数C
22、类类新增的成员:新增的成员:int z;g();虚函数虚函数f();虚函数虚函数 pb pa pcC1对象对象运行:运行:C:z=3C:z=3C:z=3C:z=3C:z=3C:z=3 Bye!11【例例】(请注意调用过程。)(请注意调用过程。)#includeclass A int x;public:A(int a)x=a;virtual void g()cout “A:x=”x endl;class B:public A int y;public:B(int a,int b):A(a)y=b;void g()cout “B:y=”y endl;class C:public B int z;p
23、ublic:C(int a,int b,int c):B(a,b)z=c;virtual void f()cout “Bye!”g();aa1.g();/pa-f();为为什么不行?什么不行?B *pb=&c1,&bb1=c1;pb-g();bb1.g();/pb-f();为为什么不行?什么不行?C *pc=&c1,&cc1=c1;pc-g();cc1.g();pc-f();从从A类继承的成员:类继承的成员:int x;g();虚函数虚函数从从B类继承的成员:类继承的成员:int y;g();虚函数虚函数C类类新增的成员:新增的成员:int z;f();虚函数虚函数 pb pa pcC1对象对
24、象运行:运行:B:y=2B:y=2B:y=2B:y=2B:y=2B:y=2Bye!12【例例】(请注意调用过程。)(请注意调用过程。)#includeclass A int x;public:A(int a)x=a;void g()cout “A:x=”x endl;class B:public A int y;public:B(int a,int b):A(a)y=b;virtual void g()cout “B:y=”y endl;class C:public B int z;public:C(int a,int b,int c):B(a,b)z=c;void g()cout “C:z=
25、”z endl;void f()cout “Bye!”g();aa1.g();/pa-f();为为什么不行?什么不行?B *pb=&c1,&bb1=c1;pb-g();bb1.g();/pb-f();为为什么不行?什么不行?C *pc=&c1,&cc1=c1;pc-g();cc1.g();pc-f();从从A类继承的成员:类继承的成员:int x;g();不是虚函数不是虚函数从从B类继承的成员:类继承的成员:int y;g();虚函数虚函数C类类新增的成员:新增的成员:int z;g();虚函数虚函数f();不是虚函数不是虚函数 pb pa pcC1对象对象运行:运行:A:x=1A:x=1C:
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 多态性 函数 课件
限制150内