深入理解虚函数和多态

1、虚函数

虚函数引入后,类会发生什么样的变化?

一个对象,只要他占用内存空间,那么这个对象的sizeof值至少是1。

类A的普通成员函数,它并不占用类对象的内存空间。

加入虚函数后,类A对象的sizeof值就变成了4。

  当一个或多个虚函数加入到一个类中之后,编译器会向类中插入一个看不见的成员变量,在类中,这个看不见的成员变量类似是下面这样的伪代码。这个看不见的成员变量有一个名字就叫虚函数表指针(简称vptr),虚函数表指针正好是4个字节,这4个字节是占用类对象的内存空间的。

虚函数引入后类会发生一些变化。

2、虚函数表

虚函数表的生成时机和生成原因?

当类A中存在至少一个虚函数的时候,在编译期间,编译器就会为类A生成一个虚函数表(virtual table),这个虚函数表会一直伴随着类A.

经过编译、链接,直到生成一个可执行文件后,这个类A以及伴随类A的虚函数表都会保存在这个可执行文件中。

在可执行文件执行的过程中,也会被一并装置到内存中。

3、虚函数表指针

虚函数表指针被赋值的时机。

虚函数表指针vptr与虚函数表vtbl之间的关系?

  对于有虚函数类A在编译的时候,编译器会向类A的构造函数中安插为vptr赋值的语句(编译期间做),是编译器默默在背后为程序员所做的事情。

当程序运行起来之后,当创建一个类A对象的时候,会执行类A的构造函数,因为构造函数中有给vptr赋值的语句,从而使vptr指向类A的vbtl。

4、类对象在内存中的布局

当生成一个类A对象的时候,就可以看一看类A对象在内存中的布局了。左侧就是类A对象的内存布局,内存布局中,编译器会向其中插入一个虚函数表指针vptr,还有两个int类型的成员变量。编译器会将vptr指向类A的虚函数表vtbl,这个是跟着类走的。vtbl中包含三个指针,这三个指针分别指向三个虚函数:vfunc、vfunc2、~A。func1、func2两个普通成员函数统统属于类A的组成部分,并不占用类A对象的内存空间。

12 = 虚函数表指针(4)+ int(4) + int(4)。

5、虚函数的工作原理和多态性的体现

常规的多态性的理解:简单来说,父类中有一个虚函数A,子类中也有一个同名虚函数A。当通过父类指针new一个子类对象,或者是通过父类引用来绑定一个子类对象的时候。如果用父类指针来调用这个虚函数,那么调用的其实是子类的虚函数。

关于多态这个概念,分两方面谈:代码实现上、表现形式上

不管谈到哪方面,谈到多态,必须存在虚函数,没有虚函数,决定不可能存在多态。

类中定义了虚函数,并且我们要调用虚函数,那么才存在多态性的可能。

5.1、代码实现方面

当调用一个虚函数的时候,可以看一下调用路线。是不是利用vptr找到vtbl,然后通过查询vtbl来找到虚函数表的入口地址,并去执行这个虚函数。如果走的是这个路线,那么就是多态。

示例代码:

5.2、表现形式方面

多态性的表现如下图

示例代码:

当有继承关系存在的时候,父类对象和子类对象他们的内存布局,以及父类与子类的虚函数表如下图所示:

  假设父类Base有f、g、h三个虚函数,子类Derive中重写了Base类中的g虚函数。因为有虚函数存在,所以编译器就会向每一个类对象中插入一个vptr。Derive类对象中指向的是Derive类的虚函数表,Base类对象中指向的是Base类的虚函数表,虚函数表是归属于类的。子类Derive有从父类Base类中继承而来的虚函数f、h和g,g虚函数被重写过了,覆盖掉了父类的虚函数g。下图中粉色的地址指向了Derive自己的虚函数g,其余两个指针指向了父类的f、h虚函数。

  假设父类Base有f、g、h三个虚函数,子类Derive中重写了Base类中的g虚函数

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

达克豪斯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值