C++课件1第6章多态性和虚函数

上传人:E**** 文档编号:90582225 上传时间:2019-06-13 格式:PPT 页数:32 大小:174KB
返回 下载 相关 举报
C++课件1第6章多态性和虚函数_第1页
第1页 / 共32页
C++课件1第6章多态性和虚函数_第2页
第2页 / 共32页
C++课件1第6章多态性和虚函数_第3页
第3页 / 共32页
C++课件1第6章多态性和虚函数_第4页
第4页 / 共32页
C++课件1第6章多态性和虚函数_第5页
第5页 / 共32页
点击查看更多>>
资源描述

《C++课件1第6章多态性和虚函数》由会员分享,可在线阅读,更多相关《C++课件1第6章多态性和虚函数(32页珍藏版)》请在金锄头文库上搜索。

1、第6章 多态性和虚函数,6.1 运算符重载 6.2 虚函数 6.3 纯虚函数和抽象类 6.4 虚析构函数,6.1 运算符重载,6.1.1 运算符重载概述 6.1.2 用成员函数重载运算符 6.1.3 用友元函数重载运算符 6.1.4 几个常用运算符的重载,6.1.1 运算符重载概述,1. 运算符重载定义 运算符重载是对已有的运算符赋予多重含义,同一个运算符作用于不同类型的数据导致不同类型的行为。 不能重载的运算符是: (1) 成员访问运算符. (2) 作用域运算符 (3) 条件运算符? : (4) 成员指针运算符* (5) 编译预处理命令的开始符号#,2. 运算符重载的规则, C+中的运算符除

2、了少数几个以外,几乎全部可以重载,不能定义新的运算符,只能重载已有的这些运算符。 重载之后运算符的优先级和结合性都不能改变。 运算符重载是针对新类型数据的实际需要,对原有运算符进行适当的改造。一般来讲,重载的功能应当与原有功能相类似,不能改变原运算符所需操作数的个数,同时至少要有一个操作数是自定义类型。 总之,当C+语言原有的一个运算符被重载之后,它原先所具有的语义并没有消失,只相当于针对一个特定的类定义了一个新的运算符。,3. 运算符重载的形式,运算符重载可以使用成员函数和友元函数两种形式。可以参考以下的经验: (1)只能使用成员函数重载的运算符有: =、()、-、new、delete。 (

3、2)单目运算符最好重载为成员函数。 (3) 对于复合的赋值运算符如+=、-=、*=、/=、&=、!=、=、%=、=、=建议重载为成员函数。 (4) 对于其它运算符,建议重载为友元函数。 除了赋值运算符外,其它运算符函数都可以由派生类继承,并且派生类还可有选择地重载自己所需要的运算符(包括基类重载的运算符)。 运算符重载的实质就是函数重载。,6.1.2 用成员函数(运算符函数)重载运算符,函数类型 operator 要重载的运算符(参数表) 若运算符是一元的,则参数表为空,此时当前对象作为此运算符的单操作数;若运算符是二元的,则参数表中有一个操作数,此时当前对象作为此运算符的左操作数,参数表中的

4、操作数作为此运算符的右操作数,依此类推。 运算符函数的定义方式同一般成员函数,对类成员的访问与一般成员函数相同,定义如下: 函数类型 类名:operator (参数表) / 运算符处理程序代码 重载运算符的使用方法同原运算符一样,只是它的操作数一定要是定义它的特定类的对象。,例题,【例6.1】用成员函数重载运算符一 【例6.2】用成员函数重载运算符二,6.1.3 用友元函数重载运算符,friend type operator (参数表); 注意友元函数不属于任何类,它没有this指针,这与成员函数完全不同。若运算符是一元的,则参数表中有一个操作数;若运算符是二元的,则参数表中有两个操作数。即在

5、用友元定义重载运算符时,所有的操作数均需要用参数来传递。友元运算符函数与成员运算符函数的主要区别在其参数个数不同。当运算符的左操作数是一个常数时,就不能利用this指针,应当用友元函数重载。 友元运算符函数的定义如下: type operator (参数表) / 运算符处理程序代码 ,例题,【例6.3】用友元函数重载运算符一 【例6.4】用友元函数重载运算符实现两字符串加法 参看教材的说明 【例6.5】用重载运算符的方法进行复数运算,6.1.4 几个常用运算符的重载(1),1运算符!和的重载 【例6.6】运算符!和的重载 2前自增和后自增运算符+的重载 前自增运算符+和后自增运算符+重载的语法

6、 operator+(); /前 operator+(int); /后 【例6.7】用成员函数重载前自增和后自增运算符。 【例6.8】用友元重载前自增和后自增,3运算符-的重载 -运算符是成员访问运算符,这种一元的运算符只能被重载为成员函数,成员访问运算符-函数重载的一般形式为: 【例6.9】重载-运算符。,6.1.4 几个常用运算符的重载(2),4赋值运算符=的重载,在正常的情况下,系统会为每一个类自动生成一个默认的赋值运算符,当然,这种赋值只限于同一个类类型说明的对象之间赋值,相当于浅拷贝构造函数。 【例6.10】赋值运算符的重载一。 【例6.11】赋值运算符的重载二。 【例6.12】赋值

7、运算符的重载三。,5逗号运算符,的重载,逗号运算符是双目运算符,和其他运算符一样,逗号运算符也可以重载。逗号运算符构成的表达式为“左操作数,右操作数”,该表达式返回右操作数的值。如果用类的成员函数来重载逗号运算符,则只带一个右运算数,而左运算数由指针this提供。 【例6.13】逗号运算符的重载,6.2 虚函数,6.2.1 为什么要引入虚函数 6.2.2 虚函数的定义与使用,6.2.1 为什么要引入虚函数,指向基类对象的指针都可以指向它的公有派生类对象,若试图指向它的私有派生类对象是被禁止的。不能将一个声明为指向派生类对象的指针指向其基类的一个对象。 声明为指向基类对象的指针,当它指向公有派生

8、类对象时,只能利用它来直接访问派生类中从基类继承来的成员,不能直接访问公有派生类中特定的成员。若想访问其公有派生类的特定成员,可以将基类指针显式类型转换为派生类指针来实现。 【例6.14】为什么要引入虚函数,6.2.2 虚函数的定义与使用,1虚函数的定义 虚函数是引入了派生概念后,用来表现基类和派生类的成员函数之间的一种关系的。虚函数定义是在基类中进行的(virtual)。在基类中的某个成员函数被声明为虚函数后,此虚函数就可以在一个或多个派生类中被重新定义。在派生类中重新定义虚函数时,都必须与基类中的原型完全相同。 虚函数是一种非静态的成员函数,说明虚函数的方法如下(在基类中说明)。 virt

9、ual 类型函数名(参数表),使用虚函数时应注意以下几点(1):,(1) 虚函数是在基类和派生类中说明相同而实现不同的成员函数,在派生类中重新定义基类中的虚函数时,可以不加virtual,因为虚特性可以传递,但函数原型必须与基类中的完全相同,否则会丢失虚特性。 (2) 基类中说明的虚函数具有下传给派生类的性质。 (3) 析构函数可以是虚函数,但构造函数则不能是虚函数。一般地将,若某类中定义有虚函数,则其析构函数也应当说明为虚函数。特别是在析构函数需要完成一些有意义的操作比如释放内存时,尤其应当如此。,(4) 在类体系中访问一个虚函数时,应使用指向基类的指针或对基类的引用,以满足运行时多态性的要

10、求。当然也可以像调用普通成员函数那样利用对象名来调用一个函数,这时会丢失虚特性。 (5) 在派生类中重新定义虚函数时,必须保证派生类中该函数的返回值和参数与基类中的说明完全一致,否则就属于重载(如果参数不同)或是一个错误(参数相同,仅返回值不同)。 (6) 若在派生类中没有重新定义虚函数,则派生类的对象将使用其基类中的虚函数代码。,使用虚函数时应注意以下几点(2):,(7) 虚函数必须是类的一个成员函数,不能是友元,但它可以是另一个类的友元。另外,虚函数不能是一个静态成员函数。 (8) 构造函数不能是虚函数。 (9) 一个类的虚函数仅对派生类中重定义的函数起作用,对其它函数没有影响。在基类中使

11、用虚函数保证了通过指向基类对象的指针调用基类的一个虚函数时,C+系统对该调用进行动态绑定,而使用普通函数则是静态绑定。,使用虚函数时应注意以下几点(3):,(10) 使用虚函数方法后,不得再使用类作用域区分符强制指明要引用的虚函数。因为此法将破坏多态性而使编译器无所适从。 (11) 若派生类中没有再定义基类中已有的虚函数,则指向该类对象的指针或引用名引用虚函数时总是引用距离其最近的一个基类中的虚函数。 (12) 若在基类的构造(析构)函数中也引用虚函数,则所引用的只能是本类的虚函数,因为此时派生类中的构造(析构)函数的执行尚未完成。,使用虚函数时应注意以下几点(4):,2. 虚函数与重载函数的

12、关系(动态多态与静态多态),(1) 重载函数要求函数有相同函数名称,不同的参数序列;而虚函数则要求这三项(函数名、返回值类型和参数序列)完全相同; (2) 重载函数可以是成员函数或友员函数,而虚函数只能是成员函数; (3) 重载函数的调用是以所传递参数序列的差别作为调用不同函数的依据;虚函数是根据对象的不同去调用不同类的虚函数; (4) 虚函数在运行时表现出多态功能,这是C+的精髓;而重载函数则在编译时表现出多态性。,【例6.15】虚函数与重载函数的关系,3虚函数的使用,定义一个基类类型的对象指针或引用便可使其在需要时指向相应的类对象,并用此指针或引用去引用该对象所对应的类中已被“虚拟化”的函

13、数,从而可以实现真正的运行时的多态性。 【例6.16】虚函数的使用举例。 【例6.17】异质链表的实现:有三个类student、teacher、staff,再定义一个链表类,此类用来存放这几个不同类的对象;并将链表list类声明为所有这些类的友元,使它可以访问它们的私有成员。,4在构造函数和析构函数中调用虚函数,在构造函数和析构函数中调用虚函数时,采用静态联编,即它们所调用的虚函数是自己的类或基类中定义的函数而不是在任何派生类中重定义的函数。同样,使用对象调用虚函数也采用静态联编。 【例6.18】在构造函数中调用虚函数,5空的虚函数,派生类并不一定必须实现基类中的虚函数,如果派生类想通过虚函数

14、机制存取虚函数,则必须建立一条从基类到派生类的虚函数路径。许多没有使用虚函数的中间类也必须声明该函数,以保证其后的派生类能使用该虚函数。可以通过声明空函数来达到此目的。 【例6.19】空虚函数,6.3 纯虚函数和抽象类,6.3.1 纯虚函数的概念 6.3.2 抽象类的概念,6.3.1 纯虚函数的概念,如果基类只表达一些抽象的概念,而并不与具体的对象相联系,但它又必须为它的派生类提供一个公共的界面,在这种情况下,可以将基类中的虚函数定义成纯虚函数。纯虚函数是一种没有具体实现的特殊的虚函数。一个基类中有一个纯虚函数时,则在它的派生类中至少有一个虚函数,否则纯虚函数是无意义的。 纯虚函数的定义格式如

15、下: virtual 类型(参数表)=0; 由于纯虚函数所在的类中没有它的定义,在该类的构造函数和析构函数中不允许调用纯虚函数,否则会导致程序运行错误,但其它成员函数可以调用纯虚函数。,6.3.2 抽象类的概念,1抽象类和具体类的概念 如果一个类至少有一个纯虚函数,那么就称该类为抽象类。能够建立实例化对象的类称为具体类,也就是不含纯虚函数的类为具体类。 抽象类的主要作用是为其所组织的继承层次结构提供一个公共的基类,它反映了公有行为的特征,其它类可以从它这里继承和实现接口,纯虚函数的实现由其具体的派生类来提供。,2对抽象类的几点规定(1),(1) 抽象类只能作为基类来派生新类,不能建立抽象类的对

16、象。 (2) 抽象类不能用作参数类型、函数返回值类型、或显式转换的类型。 (3) 可以声明指向抽象类的指针和引用,此指针可以指向它的公有派生类,进而实现多态性。 (4) 从一个抽象类派生的类必须提供纯虚函数的实现代码,或在该派生类中仍将它说明为纯虚函数,否则编译器将给出错误信息。 (5) 如果基类中含有纯虚函数,而其派生类却并没有重新定义这些纯虚函数的覆盖成员函数,那么这个派生类也是抽象类,因此也不能用来定义对象。但此情况不会影响以后的派生类。,(6) 含有纯虚函数的类中可以包含非纯虚函数,但这些非纯虚函数只能通过其派生类的对象才能被引用。 (7) 如果派生类中给出了基类所有纯虚函数的实现,则该派生类不再是抽象类。 (8) 在成员函数内可以调用纯虚函数,但在构造函数或析构函数内调用一个纯虚函数将导致程序运行错误,因为没有为纯虚函数定义代码。,2对抽象类的几点规定(2),3抽象类举例,【例6.20】计算各类形状的总面积。,6.4

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 高等教育 > 大学课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号