C++程序设计课件多态性

上传人:小**** 文档编号:240743325 上传时间:2024-05-04 格式:PPT 页数:63 大小:339KB
返回 下载 相关 举报
C++程序设计课件多态性_第1页
第1页 / 共63页
C++程序设计课件多态性_第2页
第2页 / 共63页
C++程序设计课件多态性_第3页
第3页 / 共63页
点击查看更多>>
资源描述
Software College of Northeast Normal University C+-1-C+Programming Language Dr.Zheng XiaojuanProfessorSoftware College of Northeast Normal UniversityNovember.2010Software College of Northeast Normal University C+-2-多态性 Software College of Northeast Normal University C+-3-本章内容本章内容 1 1 多态性概述多态性概述 2 2 运算符重载运算符重载 3 3 虚函数虚函数 4 4 抽象类抽象类 Software College of Northeast Normal University C+-4-1 1 多态性概述多态性概述 1.1.基本概念:同一名称,不同的功能实现方式。基本概念:同一名称,不同的功能实现方式。多态性是面多态性是面向对象的精髓,也是难点。在向对象的精髓,也是难点。在C+C+中,多态性是通过虚函中,多态性是通过虚函数来实现的。数来实现的。2.2.作用:设计出可扩充性好的程序(覆盖、重载基类的成员)作用:设计出可扩充性好的程序(覆盖、重载基类的成员);可以实现从抽象到具体,从一般到特殊(在泛泛的问题;可以实现从抽象到具体,从一般到特殊(在泛泛的问题解决方法基础上解决某一特殊的问题)。解决方法基础上解决某一特殊的问题)。3.3.赋值兼容原则:一个派生类的对象在使用上可以被当作基赋值兼容原则:一个派生类的对象在使用上可以被当作基类对象;反之则禁止,具体表现为:类对象;反之则禁止,具体表现为:派生类对象可以被赋值给基类对象;派生类对象可以被赋值给基类对象;Base b;Base b;Derive d;Derive d;b=d;b=d;Software College of Northeast Normal University C+-5-派生类的对象可以初始化基类对象的引用派生类的对象可以初始化基类对象的引用;Derive d;Derive d;Base Base b=d;b=d;派生类对象的地址可以被赋值给基类的指针:派生类对象的地址可以被赋值给基类的指针:Derive d;Derive d;Base*Base*ptrptr=&d;=&d;主主要要原原因因:派派生生类类是是基基类类的的超超集集,并并包包含含有有基基类类的的成成员员(继继承承来来的的);当当将将派派生生类类的的对对象象赋赋值值给给基基类类的的对对象象时时,系系统统将将继继承承来来的的成成员员赋赋值值给给基基类类的的对对象象;而而当当将将基基类类的的对对象象赋赋值值给给派派生生类类的的对对象象将将导导致致派派生生类类的的对对象象有未被复制成员(成员不够)。有未被复制成员(成员不够)。Software College of Northeast Normal University C+-6-指向派生类及基类对象的指针:指向派生类及基类对象的指针:在在publicpublic继承方式时,继承方式时,指指向基类对象的指针也可以指向派生类对象向基类对象的指针也可以指向派生类对象,反之则禁止。具,反之则禁止。具体表现为:体表现为:Base*Base*Pb,ObjBPb,ObjB;Derived*Derived*pd,ObjDpd,ObjD;PbPb=&=&ObjBObjB;PbPb=&=&ObjDObjD;Pd=&Pd=&ObjDObjD;Pd=&Pd=&ObjBObjB;/;/错误错误Pd=(Derived*)Pd=(Derived*)PbPb;/;/将基类对象的指针复制给派生类对象的将基类对象的指针复制给派生类对象的指针时,必须强制类型转换。指针时,必须强制类型转换。用途:基类对象的指针是用途:基类对象的指针是实现动态多态性实现动态多态性的一个手段的一个手段基类对象的指针可以基类对象的指针可以指向基类对象和派生指向基类对象和派生类对象类对象派生类对象只能指向派生类对象派生类对象只能指向派生类对象Software College of Northeast Normal University C+-7-多态性为用户提供单一接口示意图多态性为用户提供单一接口示意图Software College of Northeast Normal University C+-8-4.4.面向对象的多态性种类:面向对象的多态性种类:静态多态性:在编译过程中确定同名操作的具体操作对象。静态多态性:在编译过程中确定同名操作的具体操作对象。动态多态性:在程序运行过程中动态多态性:在程序运行过程中动态地确定动态地确定操作所针对的操作所针对的 具体对象。这种确定操作具体对象的过程就是具体对象。这种确定操作具体对象的过程就是 联编联编(binding)(binding),也称为,也称为绑定绑定。联联编编:是是指指计计算算机机程程序序自自身身彼彼此此关关联联的的过过程程。也也就就是是把把一一个个标标识识符符名名和和一一个个存存储储地地址址联联系系在在一一起起的的过过程程。用用面面向向对对象象的的术语讲,就是把一条消息和一个对象的方法相结合的过程。术语讲,就是把一条消息和一个对象的方法相结合的过程。Software College of Northeast Normal University C+-9-联编方法:联编方法:静态联编:静态联编:(静态束定,早期联编),联编工作在编译连接阶静态束定,早期联编),联编工作在编译连接阶 段完成。在编译、连接过程中,系统根据段完成。在编译、连接过程中,系统根据类型匹配类型匹配 等特征确定程序中操作调用与执行该操作的代码的等特征确定程序中操作调用与执行该操作的代码的 关系,即确定某一个同名标识到底是要调用哪一段关系,即确定某一个同名标识到底是要调用哪一段 程序代码。程序代码。如:如:函数重载、运算符重载。函数重载、运算符重载。动态联编:动态联编:(动态束定,晚期联编)联编工作在程序运行阶段动态束定,晚期联编)联编工作在程序运行阶段 完成。在编译、连接过程中无法解决的联编问题,完成。在编译、连接过程中无法解决的联编问题,要等到程序开始运行之后再来确定。要等到程序开始运行之后再来确定。如:如:虚函数虚函数 Software College of Northeast Normal University C+-10-2 2 运算符重载运算符重载 class pointclass point private:private:int x,y;int x,y;public:public:point(int xx=0,int yy=0)x=xx;y=yy;point(int xx=0,int yy=0)x=xx;y=yy;int get_x();int get_x();int get_y();int get_y();/./.;point p1(1,1),p2(3,3)point p1(1,1),p2(3,3)“p1+p2p1+p2”-需需要要编编写写程程序序来来说说明明“+”在在作作用用于于pointpoint类类对对象象时时,该该实实现现什什么么样样的的功功能能,这这就就是是运运算算符符重重载。载。Software College of Northeast Normal University C+-11-2.12.1运算符重载概述运算符重载概述1.1.需要理解的一个思想:需要理解的一个思想:(1 1)运算符是一些预定义的函数名字。)运算符是一些预定义的函数名字。(2 2)表达式与其等价的函数调用表示:)表达式与其等价的函数调用表示:惯用表示惯用表示友元函数表示友元函数表示成元函数表示成元函数表示 a+ba+boperator+(a,b)operator+(a,b)a.operator+(b)a.operator+(b)a+a+operator+(a,0)operator+(a,0)a.operator+(0)a.operator+(0)-a-aoperator-(a)operator-(a)a.operator-()a.operator-()ThisThis指针指针有有无无实现过程中首先将指定的运实现过程中首先将指定的运算表达式转化为对运算符函算表达式转化为对运算符函数的调用,运算对象转化为数的调用,运算对象转化为运算函数的参数。运算函数的参数。Software College of Northeast Normal University C+-12-2.2.运算符重载的几个问题:运算符重载的几个问题:(1 1)定定义义:运运算算符符重重载载是是对对已已有有的的运运算算符符赋赋予予多多重重含含义义,使使同同一一个个运运算算符符作作用用于于不不同同类类型型的的数数据据时时,导导致致不不同同类类型型的的行行为为。C+C+允允许许同同一一运运算算符符具具有有多多种种不不同同运运算算功功能能的的机机制。制。(2 2)为为什什么么需需要要运运算算符符重重载载:C+C+中中预预定定义义了了许许多多运运算算符符,能能够够满满足足用用户户的的一一般般应应用用要要求求,但但是是其其运运算算的的对对象象应应是是基基本本数数据据类类型型,而而不不适适用用于于用用户户自自定定义义数数据据类类型型(如如类类),),这这可可以使用运算符重载。以使用运算符重载。(3 3)含含义义:同同一一运运算算符符具具有有多多种种不不同同运运算算功功能能,如如将将“+(+(加加)”变变化化为为“*(乘乘)”;扩扩充充运运算算符符的的运运算算对对象象数数据据类类型型(如如将将+也适用对象类型也适用对象类型)。(4 4)实质:函数重载。)实质:函数重载。Software College of Northeast Normal University C+-13-(5 5)C+C+中中的的运运算算符符除除了了类类属属关关系系运运算算符符“.”、作作用用域域分分辨辨符符“:”、成成员员指指针针运运算算符符“.*.*”、sizeofsizeof运运算算符符和和三三目目运运算算符符“?:”之之外外,全全部部可可以以重重载载,而而且且只只能能重重载载C+C+中已有的运算符,不能臆造新的运算符。中已有的运算符,不能臆造新的运算符。(6 6)重重载载之之后后运运算算符符的的优优先先级级和和结结合合性性都都不不能能改改变变,也也不不能能改改变变运运算算符符的的语语法法结结构构,即即单单目目运运算算符符只只能能重重载载为为单单目目运算符,双目运算符只能重载为双目运算符。运算符,双目运算符只能重载为双目运算符。(7 7)运算符重载后的功能应当与原有功能相类似。)运算符重载后的功能应当与原有功能相类似。(8 8)重载运算符含义必须清楚,不能有二义性。)重载运算符含义必须清楚,不能有二义性。Software College of Northeast Normal University C+-14-3.3.运算符种类运算符种类:一元运算符一元运算符,二元运算符二元运算符.4.4.实现手段实现手段:借助与类运算符函数和友元运算符函数来实现借助与类运算符函数和友元运算符函数来实现.5.5.运算符函数运算符函数(语法)语法):由由关键字关键字operatoroperator后跟一运算符后跟一运算符.如如operator+()operator+()6.6.实现机制实现机制:(1 1)将)将指定的运算表达式转化为对运算符函数的调用,通过函指定的运算表达式转化为对运算符函数的调用,通过函数调用从而在函数体中达到特定的运算功能。数调用从而在函数体中达到特定的运算功能。(2)运算对象转化为运算符函数的实参。)运算对象转化为运算符函数的实参。(3)根据实参的类型来确定需要调用的函数。)根据实参的类型来确定需要调用的函数。Software College of Northeast Normal University C+-15-2.2 2.2 运运算算符符重重载载为为成成员员函函数数(类类运运算算符符函函数数):因因为为它是成员函数,从而允许它访问私有成员数据。它是成员函数,从而允许它访问私有成员数据。1.1.定定义义形形式式:类类同同于于一一般般的的成成员员函函数数并并且且也也允允许许为为内联函数,只是函数名有要求。内联函数,只是函数名有要求。operator operator(形参表形参表)函数体;函数体;Software College of Northeast Normal University C+-16-2.2.如何设计:如何设计:(1 1)函数返回值类型)函数返回值类型-与运算结果的数据类型一致;与运算结果的数据类型一致;(2 2)函数名)函数名-以以“operatoroperator运算符运算符”命名;命名;(3 3)函函数数形形参参-类类型型与与运运算算对对象象的的数数据据类类型型一一致致(一一般般采采用用引引用用),如如果果使使用用类类运运算算符符函函数数,则则个个数数为为运运算算对对象象的的个个数数减减一一;如如果果使使用用友友元元运运算算符符函函数数,则则个个数数与与运运算算对对象象的的个个数数相同;相同;(4 4)函数体)函数体-按照运算符的自然运算语义来编程。按照运算符的自然运算语义来编程。3.3.应应用用要要点点:被被重重载载的的运运算算符符如如用用于于基基本本类类型型的的数数据据运运算算,系系统统仍仍旧旧使使用用原原始始的的运运算算功功能能;只只有有被被应应用用于于指指定定的的类类的的类类型型对象运算时才转化为对运算符函数的调用。对象运算时才转化为对运算符函数的调用。Software College of Northeast Normal University C+-17-a.a.双目运算双目运算:oprdl B oprd2:oprdl B oprd2 oprdl.operator B(oprd2)oprdl.operator B(oprd2)b.b.单目运算单目运算 1)1)前置单目运算:前置单目运算:U oprdU oprd oprd.operator U()oprd.operator U()2)2)后置单目运算:后置单目运算:oprd Voprd V 为区别前置单目运算函数要带有一个整型为区别前置单目运算函数要带有一个整型(int)(int)形参。形参。oprd.operator V(int)oprd.operator V(int)Software College of Northeast Normal University C+-18-【例例1 1】双目运算符重载为成员函数。双目运算符重载为成员函数。#include class point private:float x,y;public:point(float xx=0,float yy=0)x=xx;y=yy;float get_x()return x;float get_y()return y;point operator+(point p1);/重载运算符重载运算符“+”point operator-(point p1);/和和“-”为成员函数为成员函数;Software College of Northeast Normal University C+-19-point point:operator+(point q)return point(x+q.x,y+q.y);point point:operator-(point q)return point(x-q.x,y-q.y);void main()point p1(3,3),p2(2,2),p3,p4;point p1(3,3),p2(2,2),p3,p4;/声明声明pointpoint类的对象类的对象 p3=p3=p1+p2p1+p2;/两点相加两点相加 p4=p4=p1-p2p1-p2;/两点相减两点相减coutp1+p2:x=p3.get_x(),y=p3.get_y()endl;coutp1+p2:x=p3.get_x(),y=p3.get_y()endl;coutp1-p2:x=p4.get_x(),y=p4.get_y()endl;coutp1-p2:x=p4.get_x(),y=p4.get_y()endl;创创建建一一个个临临时时的的无无名名对对象象作作为返回值,为返回值,效率高。效率高。Software College of Northeast Normal University C+-20-point point:operator+(point q)point point:operator+(point q)point p;point p;p.x=x+q.x;p.x=x+q.x;p.y=y+q.y;p.y=y+q.y;return p;return p;point point:operator-(point q)point point:operator-(point q)point p;point p;p.x=x-q.x;p.x=x-q.x;p.y=y-q.y;p.y=y-q.y;return p;return p;创建一个局部对象创建一个局部对象p(p(这时会调用构造函数这时会调用构造函数),执行,执行returnreturn语句时,会调用拷贝构造函语句时,会调用拷贝构造函数,将数,将p p的值拷贝到主调函数中的一个无名的值拷贝到主调函数中的一个无名临时对象中。当函数临时对象中。当函数operator+operator+结束时,会结束时,会调用析构函数析构对象调用析构函数析构对象p p,然后,然后p p消亡。消亡。Software College of Northeast Normal University C+-21-【例例2 2】单目运算符重载为成员函数。单目运算符重载为成员函数。#include class point private:float x,y;public:point(float xx=0,float yy=0)x=xx;y=yy;float get_x()return x;float get_y()return y;point operator+();/重载前置运算符重载前置运算符“+”point operator-();/重载前置运算符重载前置运算符“-”;Software College of Northeast Normal University C+-22-point point:operator+()if(x640)+x;if(y0)-x;if(y0)-y;return*this;Software College of Northeast Normal University C+-23-void main()point p1(10,10),p2(200,200);for(int i=0;i5;i+)coutp1:x=p1.get_x(),y=p1.get_y()endl;+p1;for(i=0;i5;i+)coutp2:x=p2.get_x(),y=p2.get_y()endl;-p2;Software College of Northeast Normal University C+-24-程序运行结果为程序运行结果为p1:x=10,y=10p1:x=10,y=10p1:x=11,y=11p1:x=11,y=11p1:x=12,y=12p1:x=12,y=12p1:x=13,y=13p1:x=13,y=13p1:x=14,y=14p1:x=14,y=14p2:x=200,y=200p2:x=200,y=200p2:x=199,y=199p2:x=199,y=199p2:x=198,y=198p2:x=198,y=198p2:x=197,y=197p2:x=197,y=197p2:x=196,y=196p2:x=196,y=196Software College of Northeast Normal University C+-25-前置单目运算符和后置单目运算符重载的区别:前置单目运算符和后置单目运算符重载的区别:函数的形参。函数的形参。语语法法规规定定,前前置置单单目目运运算算符符重重载载为为成成员员函函数数时时没没有有形形参参,而而后后置置单单目目运运算算符符重重载载为为成成员员函函数数时时,需需要要有有一一个个intint型型形形参参。这这个个intint型型参参数数在在函函数数体体中中并并不不使使用用,纯纯粹粹是是用来区别前置与后置。用来区别前置与后置。Software College of Northeast Normal University C+-26-2.3 2.3 运运算算符符重重载载为为友友元元函函数数:将将运运算算符符函函数数设设计计为为非非成成员员函函数数,同同时时为为能能访访问问privateprivate成成员员数数据据,将将它它设设计计为为友友元元函函数数(其定义和使用规则与一般的友元函数相同)。(其定义和使用规则与一般的友元函数相同)。1.1.语法:语法:friendfriend operator operator(形参表形参表)函数体;函数体;Software College of Northeast Normal University C+-27-2.2.应用要点:应用要点:(1)(1)注注意意形形参参的的定定义义与与类类运运算算符符函函数数的的不不同同;友友元元运运算算符符函函数数无无thisthis指指针针,因因而而在在函函数数体体内内必必须须通通过过对对象象名名来来使使用用privateprivate成成员员数数据据;一一般般将将一一元元运运算算符符函函数数重重载载为为类类运运算算符符函函数数(“=”也也必必须须),而而将将二二元元运运算算符符重重载载为友元运算符函数,以免出现使用错误。为友元运算符函数,以免出现使用错误。(2)(2)运运算算所所需需要要的的操操作作数数都都需需要要通通过过函函数数的的形形参参表表来来传传递递,在在参参数数表表中中形形参参从从左左到到右右的的顺顺序序就就是是运运算算符符操操作作数数的的顺序。顺序。(3)(3)有有些些运运算算符符不不能能重重载载为为友友元元,如如“=”、“()”、“”和和“-”。Software College of Northeast Normal University C+-28-a.a.双目运算:双目运算:oprdl B oprd2oprdl B oprd2 operator B(oprdloperator B(oprdl,oprd2)oprd2)b.b.单目运算单目运算:1)1)前置单目运算:前置单目运算:U oprdU oprd operator U(oprd)operator U(oprd)2)2)后置单目运算:后置单目运算:oprd Voprd V 函数的形参有两个,一个是函数的形参有两个,一个是A A类的对象类的对象oprdoprd,另一个是整型另一个是整型(int)(int)形参。形参。operator V(oprdoperator V(oprd,intint)Software College of Northeast Normal University C+-29-【例例3 3】双目运算符重载为友元重载。双目运算符重载为友元重载。#include#include class point class point private:private:float x,y;float x,y;public:public:point(float xx=0,float yy=0)x=xx;y=yy;point(float xx=0,float yy=0)x=xx;y=yy;float get_x()return x;float get_x()return x;float get_y()return y;float get_y()return y;friend point operator+(point p1,point p2);friend point operator+(point p1,point p2);friend point operator-(point p1,point p2);friend point operator-(point p1,point p2);Software College of Northeast Normal University C+-30-point operator+(point p1,point p2)point operator+(point p1,point p2)return point(p1.x+p2.x,p1.y+p2.y);return point(p1.x+p2.x,p1.y+p2.y);point operator-(point p1,point p2)point operator-(point p1,point p2)return point(p1.x-p2.x,p1.y-p2.y);return point(p1.x-p2.x,p1.y-p2.y);void main()void main()point p1(3,3),p2(2,2),p3,p4;point p1(3,3),p2(2,2),p3,p4;/声明声明pointpoint类的对象类的对象p3=p3=p1+p2p1+p2;/两点相加两点相加p4=p4=p1-p2p1-p2;/两点相减两点相减coutp1+p2:x=p3.get_x(),y=p3.get_y()endl;coutp1+p2:x=p3.get_x(),y=p3.get_y()endl;coutp1-p2:x=p4.get_x(),y=p4.get_y()endl;coutp1-p2:x=p4.get_x(),y=p4.get_y()endl;Software College of Northeast Normal University C+-31-2.4 2.4 其它运算符重载其它运算符重载 比较运算符重载(如比较运算符重载(如 ,=,=,!=!=)。)。赋值运算符重载(如赋值运算符重载(如=,+=+=,-=-=,*=,/=/=)。)。下标运算符下标运算符“”重载。重载。运算符运算符newnew和和deletedelete重载。重载。逗号运算符逗号运算符“,”重载。重载。Software College of Northeast Normal University C+-32-#includeclass counterpublic:counter()v=0;counter operator+();counter operator+(int);void print()coutvendl;private:unsigned v;counter counter:operator+()v+;return*this;counter counter:operator+(int)counter t;t.v=v+;return t;void main()counter c;for(int i=0;i8;i+)c+;c.print();for(i=0;i8;i+)+c;c.print();Software College of Northeast Normal University C+-33-3 3 虚函数虚函数 3.13.1为什么要引入虚函数为什么要引入虚函数#include class base public:void who()coutthis is the class of base!endl;class derive1:public base public:void who()coutthis is the class of derive1!endl;Software College of Northeast Normal University C+-34-class derive2:public basepublic:void who()coutthis is the class of derive2!who();ptr=&obj1;ptr-who();ptr=&obj2;ptr-who();obj1.who();obj2.who();return 1;通过指针引起的普通成员通过指针引起的普通成员函数调用,仅仅与指针的函数调用,仅仅与指针的类型有关,而与指针正指类型有关,而与指针正指向什么对象无关。向什么对象无关。此程序的意图是用此程序的意图是用ptrptr指针分别指向不同的对象,指针分别指向不同的对象,以便执行不同对象所对应的类的成员函数。以便执行不同对象所对应的类的成员函数。Software College of Northeast Normal University C+-35-this is the class of base!this is the class of base!this is the class of base!this is the class of derive1!this is the class of derive2!为达到目的采取的方法:为达到目的采取的方法:(1 1)采用显式的方式调用派生类的函数成员)采用显式的方式调用派生类的函数成员例如:例如:obj1.who()obj1.who()或或obj2.who()obj2.who()(2 2)采用对指针的强制类型转换的方法,)采用对指针的强制类型转换的方法,例如:例如:(derive1*)ptr)-who()(derive1*)ptr)-who()或或(derive2*)ptr)-who()(derive2*)ptr)-who()Software College of Northeast Normal University C+-36-关于类型转换关于类型转换char ch;int i;1Bytech=(char)i;i=(int)ch;1Byte1Byte1Byte1ByteSoftware College of Northeast Normal University C+-37-FishFish对象内存布局对象内存布局AnimalAnimal对象内存对象内存FishFish继承部分继承部分thisthis指针指针FishFish对象的对象的内存内存图图 FishFish对象内存布局对象内存布局Software College of Northeast Normal University C+-38-本来使用对象指针是为了表达一种动态的本来使用对象指针是为了表达一种动态的性质,即当指针指向不同对象时执行不同的操性质,即当指针指向不同对象时执行不同的操作,但并没有起到这种作用。作,但并没有起到这种作用。要实现这种功能要实现这种功能-引入引入虚函数虚函数的概的概念。只需将基类的念。只需将基类的who()who()函数声明为虚函数即函数声明为虚函数即可。可。Software College of Northeast Normal University C+-39-3.2 3.2 虚函数的定义及使用虚函数的定义及使用 1.1.虚虚函函数数的的定定义义:在在基基类类中中以以virtualvirtual加加以以修修饰饰的的非非静静态态成成员员函函数并且在一级或多级派生类中被重新定义的成员函数。数并且在一级或多级派生类中被重新定义的成员函数。2.2.为为什什么么需需要要虚虚函函数数:当当派派生生类类覆覆盖盖基基类类中中同同名名成成员员函函数数时时,为为避免调用时的二义性可以采用静态或动态联编。避免调用时的二义性可以采用静态或动态联编。(1 1)静静态态联联编编:采采用用对对象象名名(借借助助同同名名覆覆盖盖原原则则:派派生生类类覆覆盖盖基基类类中中同同名名成成员员;未未强强行行指指明明则则为为派派生生类类同同名名成成员员;如如访访问问被被同同名名覆覆盖盖的的同同名名基基类类成成员员,应应使使用用基基类类名名限限定定。)或或类类名名限限定定(根根据据定义时的类型编译调用代码定义时的类型编译调用代码)(2 2)动动态态联联编编:采采用用基基类类对对象象的的指指针针或或引引用用(因因为为有有些些问问题题在在设设计计时时不不能能预预知知或或为为提提高高程程序序灵灵活活性性,必必须须使使用用动动态态联联编编),此此时时根据指针指向的目标对象的类型编译调用代码。根据指针指向的目标对象的类型编译调用代码。Software College of Northeast Normal University C+-40-3.3.如何实现动态联编:在基类中将同名成员函数定义为虚函如何实现动态联编:在基类中将同名成员函数定义为虚函数;调用这些同名函数时应采用数;调用这些同名函数时应采用基类对象的指针或引用基类对象的指针或引用。4.4.虚函数的特点:虚函数的特点:(1 1)具有继承性)具有继承性-在基类中一旦定义为虚函数,在以后的在基类中一旦定义为虚函数,在以后的各级派生类中同名成员函数自动也为虚函数而各级派生类中同名成员函数自动也为虚函数而不管是否有不管是否有virtualvirtual修饰修饰;(2 2)虚函数的本质)虚函数的本质:是替换(或称覆盖)而非重载定义。是替换(或称覆盖)而非重载定义。(3 3)派生类中如没有重新定义虚函数,则将继承基类中的虚)派生类中如没有重新定义虚函数,则将继承基类中的虚函数,此时系统仍旧采用静态联编;析构函数可以为虚函函数,此时系统仍旧采用静态联编;析构函数可以为虚函数但构造函数不能为虚函数,并且虚函数不适用于有大量数但构造函数不能为虚函数,并且虚函数不适用于有大量for,do-while,whilefor,do-while,while语句的场合以免频繁调用,降低速度。语句的场合以免频繁调用,降低速度。Software College of Northeast Normal University C+-41-5.5.如何调用虚函数:采用基类对象的指针或引用并如何调用虚函数:采用基类对象的指针或引用并根根据该指针当前的目标对象的类型据该指针当前的目标对象的类型,动态地调用此对,动态地调用此对象所属的类中的虚函数。象所属的类中的虚函数。6.6.应用要点:应用要点:在调用虚函数时是根据基类的指针当前所指向的目在调用虚函数时是根据基类的指针当前所指向的目标对象而非该指针在定义时的类类型;标对象而非该指针在定义时的类类型;7.7.必须使用虚函数的场合:设计时无法预知所需要使必须使用虚函数的场合:设计时无法预知所需要使用的函数。用的函数。Software College of Northeast Normal University C+-42-8.8.定义语法:定义语法:virtualvirtual只修饰成员函数的说明而非函数体的定义只修饰成员函数的说明而非函数体的定义 virtualvirtual(形参表形参表)函数体函数体 注意:注意:(1 1)虚虚函函数数的的声声明明只只能能出出现现在在类类声声明明中中的的函函数数原原型型声声明明中中,而而不能出现在成员的函数体实现的时候。不能出现在成员的函数体实现的时候。(2 2)当当基基类类中中的的某某个个成成员员函函数数被被声声明明为为虚虚函函数数后后,此此虚虚函函数数就就可可以以在在一一个个或或多多个个派派生生类类中中被被重重新新定定义义,在在派派生生类类中中重重新新定定义义时时,其其函函数数原原型型,包包括括返返回回类类型型、函函数数名名、参参数数个个数数、参参数数类类型以及参数的顺序都必须与基类中的原型完全相同型以及参数的顺序都必须与基类中的原型完全相同。virtualvirtual告诉编译器告诉编译器:这个成员函数在派生类中这个成员函数在派生类中可能会有不同实现,当用这个成员函数操作指可能会有不同实现,当用这个成员函数操作指针或引用所标识的对象时,对这个成员函数调针或引用所标识的对象时,对这个成员函数调用的束定应延迟到程序运行时再进行。用的束定应延迟到程序运行时再进行。Software College of Northeast Normal University C+-43-(3)(3)运行过程中的多态要满足运行过程中的多态要满足3 3个条件:个条件:a.a.类型兼容原则类型兼容原则b.b.声明虚函数声明虚函数c.c.由成员函数来调用或者是通过指针、引由成员函数来调用或者是通过指针、引用来访问虚函数。用来访问虚函数。Software College of Northeast Normal University C+-44-关于函数的覆盖与隐藏关于函数的覆盖与隐藏#include class Animalpublic:void eat()coutanimal eatendl;void sleep()coutanimal sleependl;void breathe()coutaniaml breatheendl;class Fish:public Animalpublic:breathe()coutfish bubbleendl;void main()Fish fh;fh.breathe();breathe()Animal:breathe();coutfish bubbleendl;:作用域标识符,用于指明一个函数属于那个类或作用域标识符,用于指明一个函数属于那个类或一个数据成员属于那个类。一个数据成员属于那个类。所谓隐藏是指派生类中具有与基类同名的函数所谓隐藏是指派生类中具有与基类同名的函数(不考虑参数列表是否相同),从而在派生类(不考虑参数列表是否相同),从而在派生类中隐藏了基类的同名函数。中隐藏了基类的同名函数。构成函数覆盖的条件:构成函数覆盖的条件:派生类函数与基类函数完全相同,基类没有派生类函数与基类函数完全相同,基类没有使用使用virtual。派生类的函数与基类函数同名,但参数列表派生类的函数与基类函数同名,但参数列表不同,不管基类是否使用不同,不管基类是否使用virtual。当隐藏发生时可使用基类名当隐藏发生时可使用基类名:函数名函数名(参数)参数)调用基类的被隐藏函数。调用基类的被隐藏函数。Software College of Northeast Normal University C+-45-函数的覆盖函数的覆盖Derived:xfn(int i)Derived:xfn(int i)Base:yfn(float i)Derived:yfn(float i)Base:zfn()Derived:zfn()#include class Basepublic:virtual void xfn(int i)coutBase:xfn(int i)eddl;void yfn(float i)coutBase:yfn(float i)eddl;void zfn()coutBase:zfn()eddl;class Derived:public Base void xfn(int i)coutDerived:xfn(int i)eddl;void yfn(int i)coutDerived:yfn(float i)eddl;void zfn()coutDerived:zfn()xfn(5);pD-xfn(5);pB-yfn(3.14f);pD-yfn(3.14f);pB-zfn();pD-zfn();函数的覆盖(函数的覆盖(override)override)是发生是发生在父类与子类之间的。在父类与子类之间的。重载发生在同一类。重载发生在同一类。构成函数覆盖的条件:构成函数覆盖的条件:基类函数必须是虚函数。基类函数必须是虚函数。发生覆盖的两个函数要分别位发生覆盖的两个函数要分别位于派生类和基类中。于派生类和基类中。函数名称和参数列表必须完全函数名称和参数列表必须完全相同。相同。Software College of Northeast Normal University C+-46-虚函数与多态性虚函数与多态性#include class Animalpublic:void eat()coutanimal eatendl;void sleep()coutanimal sleependl;void breathe()coutaniaml breatheendl;class Fish:public Animalpublic:breathe()coutfish bubblebreathe();void main()Fish fh;Animal*pAn;pAn=&fh;fn(pAn);C+C+编译器进行了类型转换,编译器进行了类型转换,pAnpAn保存的就是保存的就是AnimalAnimal对象地址。对象地址。C+编译器在编译时就确定了编译器在编译时就确定了哪个函数被调用,这叫做早期哪个函数被调用,这叫做早期绑定绑定(early bindingearly binding)。Software College of Northeast Normal University C+-47-#include class Animalpublic:void eat()coutanimal eatendl;void sleep()coutanimal sleependl;virtual void breathe()coutaniaml breatheendl;class Fish:public Animalpublic:breathe()coutfish bubblebreathe();void main()Fish fh;Animal*pAn;pAn=&fh;fn(pAn);虚函数与多态性虚函数与多态性当当当当C+C+编译器在编译的时候,发编译器在编译的时候,发编译器在编译的时候,发编译器在编译的时候,发现现现现AnimalAnimal类的类的类的类的breathe()breathe()函数是函数是函数是函数是虚函数,这个时候虚函数,这个时候虚函数,这个时候虚函数,这个时候C+C+就会采用就会采用就会采用就会采用迟绑定(迟绑定(迟绑定(迟绑定(late bindinglate binding)的技术,)的技术,)的技术,)的技术,在运行时,依据对象的类型(在在运行时,依据对象的类型(在在运行时,依据对象的类型(在在运行时,依据对象的类型(在程序中,我们传递的程序中,我们传递的程序中,我们传递的程序中,我们传递的FishFish类对象类对象类对象类对象的地址)来确认调用的哪一个函的地址)来确认调用的哪一个函的地址)来确认调用的哪一个函的地址)来确认调用的哪一个函数,这种能力就叫做数,这种能力就叫做数,这种能力就叫做数,这种能力就叫做C+C+的多态的多态的多态的多态性。性。性。性。Software College of Northeast Normal University C+-48-虚函数与多态性虚函数与多态性在基类的函数前加上在基类的函数前加上virtual关键字,在派生类中重关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用写该函数,运行时将会根据对象的实际类型来调用相应的函数,如果对象类型是派生类,就调用派生相应的函数,如果对象类型是派生类,就调用派生类的函数,如果对象类型是基类,就调用基类的函类的函数,如果对象类型是基类,就调用基类的函数。数。Software College of Northeast Normal University C+-49-【例例5 5】使用虚函数。使用虚函数。#include class base public:virtual void who()/虚函数声明虚函数声明 coutthis is the class of base!endl;class derive1:public basepublic:void who()/重新定义虚函数重新定义虚函数 coutthis is the class of derive1!endl;Software College of Northeast Normal University C+-50-class derive2:public basepublic:void who()/重新定义虚函数重新定义虚函数coutthis is the class of derive2!who();ptr=&obj1;ptr-who();ptr=&obj2;ptr-who();return 1;程序运行结果程序运行结果 this is the class of base!this is the class of derive1!this is the class of derive2!ptrptr指针指向哪个对象指针指向哪个对象是在执行过程中确定是在执行过程中确定的,所以体现的是一的,所以体现的是一种动态的多态性。种动态的多态性。Software College of Northeast Normal University C+-51-3 3多继承中的虚函数多继承中的虚函数【例例6 6】多继承中使用虚函数。多继承中使用虚函数。#include class base1 public:virtual void who()/函数函数who()who()为虚函数为虚函数 coutthis is the class of base1!endl;class base2 public:void who()/此函数此函数who()who()为一般的函数为一般的函数 coutthis is the class of base2!endl;Software College of Northeast Normal University C+-52-class derive:public base1,public base2public:void who()coutthis is the class of derive!who();ptr2=&obj2;ptr2-who();ptr1=&obj3;ptr1-who();ptr2=&obj3;ptr2-who();return 1;程序执行的结果为程序执行的结果为this is the class of base1!this is the class of base2!this is the class of derive!this is the class of base2!who()who()在不同的场合在不同的场合呈现不同的性质呈现不同的性质Software College of Northeast Normal University C+-53-3.3 3.3 虚函数的限制虚函数的限制 只只有有成成员员函函数数才才能能声声明明为为虚虚函函数数。因因为为虚虚函函数数仅仅适适用用于于有有继继承关系的类对象,所以普通函数不能声明为虚函数。承关系的类对象,所以普通函数不能声明为虚函数。虚虚函函数数必必须须是是非非静静态态成成员员函函数数。这这是是因因为为静静态态成成员员函函数数不不受受限于某个对象。限于某个对象。内内联联函函数数不不能能声声明明为为虚虚函函数数。因因为为内内联联函函数数不不能能在在运运行行中中动动态态确确定定其其位位置置。即即使使虚虚函函数数在在类类的的内内部部定定义义,编编译译时时,仍仍将将其其看作非内联的。看作非内联的。构造函数不能声明为虚函数。多态是指不同的对象对同一消构造函数不能声明为虚函数。多态是指不同的对象对同一消息有不同的行为特性。虚函数作为运行过程中多态的基础,主息有不同的行为特性。虚函数作为运行过程中多态的基础,主要是针对对象的,而构造函数是在对象产生之前运行的,因此,要是针对对象的,而构造函数是在对象产生之前运行的,因此,虚构造函数是没有意义的。虚构造函数是没有意义的。析析构构函函数数可可
展开阅读全文
相关资源
相关搜索

最新文档


当前位置:首页 > 商业管理 > 营销创新


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!