C++对象模型(Object Model)--关于vptr(虚函数指针)和vtbl(虚函数表)

  1. 子类继承父类, 父类的变量被子类继承, 也就是在内存上子类继承父类的变量
  2. 子类继承父类, 父类的函数被子类继承, 不是继承父类函数的内存大小, 而是继承父类函数的调用权

假设A是父类, B是继承于A的子类

  • 如果A有虚函数, B会继承A的函数的调用权, 因此B不可能没有虚函数, 因此, 如果父类有虚函数, 那么子类一定有虚函数

例子:
在这里插入图片描述
在上图的左下角, 有个p, 这个p是这样来的C* p = new C;
在c语言时代, 如果要调用一个函数, 编译器会把代码编译成CALL XXX(XXX是地址), 然后去这个地址执行, 之后进行return返回, 这种行为称为静态绑定
在C++中, 是这样的:
先通过p指针指向的地址里找到vptr, 然后通过vptr找到虚函数表, 也即vtbl, 然后通过vtbl找到对应函数的地址, 最后进行调用. 这种行为叫做动态绑定(dynamic binding). 下图是过程:
在这里插入图片描述
用c语言模拟调用过程的代码:

(*(p->vptr)[n])(p);
或者
(* p->vptr[n])(p); //下面也可以, 是因为运算符优先级的关系

继承和虚函数结合结合起来, 其实就是多态(polymorphism)
例子:
假设C继承于B, B继承于A, 如下图, 我们把A比作形状, B类比矩形, C类比正方形
在这里插入图片描述
假设我们想要在一个list中存储不同的形状, 没有哪个容器可以存放内存大小不一样的类实例, 那么我们只能放指针, 结合向上转型, 于是我们放父类的指针.
当我们希望画出某个形状的时候, 我们可以直接通过地址, 找到指针指向的对象, 然后通过虚指针, 找到对应的函数, 如下下图.
在这里插入图片描述
在这里插入图片描述

2. 关于动态绑定

为什么

B b;
A a = (A)b;
a.vfunc1(); //静态绑定

是静态绑定呢?
首先要明确, 动态绑定有三点要求:

  1. 函数调用是指针, 意思是需要一个指针指向那个类
  2. 有继承关系
  3. 有虚函数

上面的是用了对象a去调用函数, 因此是静态绑定.
我个人觉得:
首先你b强转为了A类, 编译器会把b的东西都转成a的类型, 也就是说, 如果b中有一个类型是double, A类中声明的地址分布对应这个类型是int的话, 那么就会转为int, 诸如此类.
然后b就彻底成为A类型了(当然深层的东西我不知道会不会转, 比如说b中的虚函数指针), 此时用a.vfunc1(), 是用对象去调用, 这个对象绑定的函数地址在编译时已经确定了, 因此汇编代码就是call xxx
对比

pa = &b;
pa->vfunc1(); //动态绑定

这里是pa指向b的地址, 当用地址去寻找函数的时候,编译器行为就不一样了, 就会用虚函数指针去找虚函数表等一系列行为.
(以上纯属我个人理解)
在这里插入图片描述
在这里插入图片描述
测试一下:

#include <iostream>
using namespace std;

class A{
public:
    virtual void vfunc1(){
        cout << "A" << endl;
    }
};

class B: public A{
public:
    virtual void vfunc1(){
        cout << "B" << endl;
    }
};
int main(int argc, char *argv[]){
    B b;
    A a = (A)b;
    a.vfunc1(); //静态绑定

    A* pa = new B;
    pa->vfunc1(); //动态绑定

    pa = &b;
    pa->vfunc1(); //动态绑定

    return 0;
}

输出:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

zedjay_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值