内容来自:https://www.bilibili.com/video/av19151507/?p=17
B继承A,C继承B,C包含有A和B的数据,B包含有A的数据。
虚指针(vptr):对于第一个指针,只要class里有虚函数,数据里就会包含有一个指针,无论多少个虚函数都只有一个指针,所以用sizeof(A)测试A的大小时 会比无虚函数的A多4个字节(32为系统)。
继承的是父类数据 和其函数的调用权,父类有虚函数,子类一定有,也包括那根指针。
对于ABC三个类,一共有8个函数,4个虚函数,4个非虚函数。
虚表(vtbl):虚指针所指的那个表就是虚表,虚表里放的都是函数指针,指向虚函数所在的位置。
A有两个虚函数,所以虚表有两个虚指针。
B继承自A,有两个虚函数,重写了其中一个虚函数,还是两个,所以虚表有两个虚指针。
C继承自B,有两个虚函数,重写了其中一个虚函数,还是两个,所以虚表有两个虚指针。
对象调用虚函数时 底层所发生的的调用顺序:使用new C
时便会得到图中的那个虚指针p,这个指针不是直接指向内存空间(传统调用就是直接跳转到那个地址,叫静态绑定),而是先指向一个虚表,虚表里放的才是虚函数的真正内存位置(动态绑定,这是面向对象的设计的关键点)。
上面的流程可以用如下C代码展示:
首先通过对象的虚指针p找到虚表,然后找到虚表里第n个对应的虚函数的地址,传入参数p(对于传入的这个p,我感觉有点this的效果)。其中n为虚函数的真实地址所在虚表中的位置,也是程序员写的虚函数的顺序0,1,2。。。
编译器在编译调用call
时,分两种考虑,静态绑定和动态绑定。动态绑定需要满足三个条件:
- 通过指针调用
- 指针up-cast,向上造型
- 调用虚函数
虚函数的这种用法也叫 多态polymorph
虚指针,虚表,虚函数,多态,动态绑定,虚机制 指的都是同一件事情
。
举例说明
设计power point,画图形状的类。
抽象出一个类叫 shape, 子类可以有square、rectangle、circular、ellipse等
list<A*>myList;
用父类创建指针容器,指针可以指向任何子类型,也叫up-cast(向上造型)
其中draw函数为 “画” 这个动作,父类声明,子类重写,所以设计成虚函数。