1小时精通c++面向对象编程

五、多态性和虚函数

5.1 多态性

发出同样的消息被不同类型的对象接受导致完全不同的行为

多态可分为:静态多态性与动态多态性(必须存在于继承的环境之中)

5.1.1 函数重载

在类中,构造函数可以重载,普通成员函数也可以重载

5.1.2 示例

图5-1 构造函数重载

5.1.3 哪些运算符可以重载?

图5-2 运算符重载

5.1.4 重载为类的成员函数

重载一元运算符,不再显式说明参数

重载二元运算符,只显式说明一个参数;该参数为操作数的右操作数,左操作数由this指针(指向调用该成员函数的对象)提供

重载为成员函数时,隐含了一个参数(this指针)

5.1.5 示例

图5-3 重载成员函数

5.1.6 重载为友元函数

重载为友元函数时,没有隐含的参数this指针,即不改变原有运算符的语法结构

下列运算符不能重载为友元函数:=、()、[]、->

重载为友元函数的运算符重载函数的格式:friend <类型说明符> operator <运算符>(<参数表>)

5.1.7 示例

图5-4 重载友元函数

5.2 静态束定(静态联编)

静态联编是指联编工作在编译阶段完成的,这种联编过程是在程序运行之前完成的,又称为早期联编。要实现静态联编,在编译阶段就必须确定程序中的操作调用(如函数调用)与执行该操作代码间的关系,确定这种关系称为束定,在编译时的束定称为静态束定。静态联编对函数的选择是基于指向对象的指针或者引用的类型。其优点是效率高,但灵活性差

5.2.1 静态联编示例

图5-5 静态联编

从示例可以看出,通过对象指针进行的普通成员函数的调用,仅仅与指针的类型有关,而与此刻指针正指向什么对象无关。要想实现当指针指向不同对象时执行不同的操作,就必须将基类中相应的成员函数定义为虚函数,进行动态联编

5.3 动态束定(动态联编)

动态联编是指联编在程序运行时动态地进行,根据当时的情况来确定调用哪个同名函数,实际上是在运行时虚函数的实现。这种联编又称为晚期联编,或动态束定。动态联编对成员函数的选择是基于对象的类型,针对不同的对象类型将做出不同的编译结果。C++中一般情况下的联编是静态联编,但是当涉及到多态性和虚函数时应该使用动态联编。动态联编的优点是灵活性强,但效率低

实现动态联编需要同时满足以下三个条件:

1必须把动态联编的行为定义为类的虚函数

2类之间应满足子类型关系,通常表现为一个类从另一个类公有派生而来

3必须先使用基类指针指向子类型的对象,然后直接或者间接使用基类指针调用虚函数

5.3.1 动态联编示例

图5-6 动态联编示例

5.4 虚函数

虚函数是动态束定的基础

虚函数是非static成员函数

格式:virtual<类型说明符> <函数名>(<参数表>)

若类中一成员函数被说明为虚函数,则该成员函数在派生类中可能有不同的实现。当使用该成员函数操作指针或引用所标识的对象时,对该成员函数调用可采用动态束定方式

动态束定只能通过指针或引用标识对象来操作虚函数。如果采用一般类型的标识对象来操作虚函数,则将采用静态束定方式调用虚函数

5.4.1 示例

图5-7 虚函数与动态联编

解释一下上面的程序,B从A公有继承,B是A的子类型,B中的act1()为虚函数,b.act2()调用A中的act2(),进一步调用act1(),产生动态束定,运行时选择B::act1()

5.5 纯虚函数

在基类中不能为虚函数给出一个有意义的实现时,可将其声明为纯虚函数,其实现留待派生类完成

5.5.1 纯虚函数定义格式

图5-8 纯虚函数定义格式

5.5.1 示例

图5-9 纯虚函数

5.6 抽象类

带有纯虚函数的类称为抽象类

抽象类只能作为基类使用,其纯虚函数的实现由派生类给出;但派生类仍可不给出纯虚函数的定义,继续作为抽象类存在

抽象类不能定义对象,一般将该类的构造函数说明为保护的访问控制权限

在成员函数内可以调用纯虚函数,但在构造函数或析构函数内不能调用纯虚函数(纯虚函数没有实现代码)

5.6.1 抽象类的作用

1用作基类:在一个继承层次结构中,提供一个公共的根,并基于抽象类的操作设计出对抽象类所描述的一类对象进行操作的公共接口,其完整的实现由派生类完成

2用作指针或引用的基类型:保证进入继承层次的每个类都具有(提供)纯虚函数所要求的行为

图5-10 纯虚函数调用方法

5.6.2 示例

图5-11 纯虚函数

图5-12 纯虚函数(续)

图5-13 纯虚函数(续)

5.6.3 说明

图5-14 抽象类

5.7 虚析构函数

在析构函数前加关键字virtual进行说明,则该析构函数称为虚析构函数

如果一个类的析构函数被说明为虚析构函数,则它的派生类中的析构函数也是虚析构函数,不管它是否使用了关键字virtual进行说明

子类型化要求析构函数被声明为虚函数,尤其是在析构函数要完成一些有意义的工作时,构造函数不能被声明为虚函数

目的:使用delete运算符删除一个对象时,能保证析构函数被正确地执行

图5-15 虚析构函数格式

5.7.1 示例

图5-16 虚析构函数

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏猿人谷

C++重要知识点小结---2

C++重要知识点小结--1 :http://www.cnblogs.com/heyonggang/p/3246631.html 1.C++允许程序员声明一个不能...

20070
来自专栏塔奇克马敲代码

第 14 章 重载运算与类型转换

25360
来自专栏别先生

Scala学习教程笔记二之函数式编程、Object对象、伴生对象、继承、Trait、

1:Scala之函数式编程学习笔记: 1:Scala函数式编程学习: 1.1:Scala定义一个简单的类,包含field以及方法,创建类的对象,并且调用...

32960
来自专栏码云1024

c++ 深入理解虚函数

60960
来自专栏企鹅号快讯

Python网络爬虫之正则表达式

正则表达式非Python独有,在Python中通过re库模块实现。 ? 下面是一些常见的匹配模式 ? re.match re.match尝试从字符串的起始位置匹...

198100
来自专栏编程理解

排序算法(七):快速排序

快速排序是通过分治的方式,根据选定元素将待排序集合拆分为两个值域的子集合,并对子集合递归拆分,当拆分后的每个子集合中元素个数为一时,自然就是有序状态。

11730
来自专栏GopherCoder

Python 强化训练:第三篇

12940
来自专栏用户2442861的专栏

java中的内部类总结

http://www.cnblogs.com/nerxious/archive/2013/01/24/2875649.html

10130
来自专栏拭心的安卓进阶之路

深入理解 Java 反射:Class (反射的入口)

深入理解 Java 反射系列: 深入理解 Java 反射:Class (反射的入口) 深入理解 Java 反射:Field (成员变量) 深入理解 Java ...

295100
来自专栏流媒体

C++多态

当类存在虚函数时,编译器会为该类维护一个表,这个表就是虚函数表(vtbl),里面存放了该类虚函数的函数指针。在构造类的时候增加一个虚表指针(vptr)指向对应的...

12430

扫码关注云+社区

领取腾讯云代金券