【c++初级】详解多态

目录

一.多态的作用和概念

二.多态的实现条件

三.重载,重写,重定义的差异

四.多态的本质

五.析构函数在多态内部的作用

六.抽象函数

七.一个可以直观看虚表调试的思路

八.虚表的底层(了解即可)

九.常见问题


一.多态的作用和概念

我们实现多态的目的是为了实现不同对象调用同一行为产生不同效果。比如说针对买票这一动作,学生买票的价格是半价,普通人 买票则还是正常价,这就实现了同一行为不同对象拥有不同结果。

二.多态的实现条件

1.要实现虚函数重写

2.必须通过指针或引用去调用虚函数。

这里简单说一下虚函数重写的条件:

a.声明其为虚函数。

b.函数名,参数和返回值都相同。

这里有两个特例:首先基类声明为虚函数后,子类不加virtual也可以。因为虚函数重写是接口继承,就意味着会把参数列表也继承下来。还有一个特例重写的协变,也就是返回值可以是基类对象的指针或者引用。

三.重载,重写,重定义的差异

1.重载:两个函数在同一作用区域,函数名/参数相同

2.重写:两个函数一个在基类一个在子类,函数名,参数,和返回值 一致(协变除外),都是虚函数 

3.重定义:函数名相同,不构成重写的就是重定义

四.多态的本质

通过对继承的理解我们可以知道类内部的存储方式,当我们实现多态的时候,会在原来内存布局的基础上多出一个东西,虚函数表。比如说这里有基类A,子类B.这里画 的是B的内存布局,_a是A的变量,_B是B的变量,在内存的最上方(这个位置也可能是最下方,由编译器决定)。虚函数表内部存的是一个地址。可以这个储存的地址找到所有的虚函数,因为它是一个函数指针数组,他可以通过数组的方式找到相应的虚函数包括继承下来虚函数的和内部自身的虚函数,当某个函数实现了多态,那么虚函数表对应位置就只会记录子类所对应的虚函数而不会保存基类的虚函数。注意,只有虚函数才会放到虚函数表里,普通函数的位置和正常变量一致,调用也是直接去对应函数的地址去调用。

 

多态函数和普通函数实现时的本质区别还有一个就是,普通函数的地址在编译时就已经确定了。但是虚函数的地址只有在运行时通过虚函数表才能找到,是运行时确定的。

五.析构函数在多态内部的作用

我们在继承中使用析构函数的时候,对于不同的析构函数,最好实现成多态,析构函数名会被统一处理成destructor,析构函数写成多态有什么含义吗。当我们用父类指针指向子类对象的时候。析构这个子类对象的时候我们知道需要先析构子类对象自己,在析构继承下来的类对象。如果我们不实现多态,因为调用的指针是父类的,他会默认去调用父类的析构对象。这样就少析构一次。

六.抽象函数

抽象函数也叫纯虚函数以 =0 结尾,抽象函数在重写前是不能实例化对象的,他相当于是一个函数接口。

七.一个可以直观看虚表调试的思路

首先明确一点,虚函数表是函数指针数组。我们拿到虚表的地址很简单,但我们想看虚表里的内容。也就是四个字节四个字节的看,看每一个虚函数的地址。我们可以通过把它转换成int型,在解引用。但我们不能直接强转,因为编译器不支持这种强转方式。但我们可以通过先取地址在把地址转换成int*再解引用,这样就能拿到头四个字节的内容。

八.虚表的底层(了解即可)

虚表储存的其实并不直接是虚函数的地址,首先我们要知道普通函数时怎么调用的。我们调用函数的地址的时候,先跳转到一个中间地址,中间地址存放的值其实才是这个函数真正的地址,再跳转过去进行函数内部的各种操作。

那么基类怎么调用自己的虚函数呢?虚表里存的虚函数地址其实就是上文刚刚说过中间地址,找到中间地址后,在跳转到真正的函数位置

至于子类调用基类的虚函数则稍稍复杂一点。我们找到虚表里的虚函数地址后跳转到一个中间地址,中间地址存放着另一个地址,这个地址存放的是偏移量。偏移量是基类内存的大小,之所以有这个偏移量,是因为调用这个虚函数的指针起始位置是子类的起始位置。但如果想调用父类的内容,父类的所用内容都不在这个指针的范围内,于是先需要通过一个偏移量把指针挪到父类的起始位置。这样就能找到父类内部的内容了。然后寄存偏移量的下一行地址存放的就是普通调用的时候的中间地址,后面就和普通调用一样了,有点绕。

九.常见问题

1.虚函数无法成为内联函数,但是写上不会报错,因为内联是对编译器的一个建议,内联函数是没有地址的,因为他就地展开,无法放进虚表。

2.静态函数不能是虚函数。没有this指针,静态成员函数是可以通过类名直接调用的。并且是编译时决议,但是虚函数是运行时决议

3.构造函数不能是虚函数,因为虚表指针在初始化列表阶段形成,,没有构造函数就无法创建虚表指针

4.虚表是编译阶段形成的,虚表指针是初始化列表阶段形成的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值