本文转自头条号C语言基础
前言
虚函数表: C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。
对C++ 了解的人都应该知道虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。简称为V-Table。在这个表中,主是要一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其内容真实反应实际的函数。这样,在有虚函数的类的实例中这个表被分配在了这个实例的内存中。 C++的编译器应该是保证虚函数表的指针存在于对象实例中最前面的位置。这意味着我们通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。
无继承的虚函数表
有类如下:
对象--->虚函数表地址
输出
对*(int*)*(int*)(&b)的理解(看到后刺激不?)
如上图所示:实际就是一个指向指针的指针,需要两次解引用才能得到存储在虚函数表中的函虚数指针。
整个解析流程
b:Base类对象;
&b:Base类对象的首地址,因为 C++的编译器应该保证虚函数表的指针存在于对象实例中最前面的位置,也就是该地址存储的内容应该是虚函数表的地址;
(int *)(&b):对其进行强制类型转换成(int *)的目的是当对其执行间接访问操作时,可以访问到以该地址开始的连续四个字节的内存空间,因为指针总是要占四个字节的。
*(int *)(&b):第一次解引用,指向虚函数表,其值为虚函数表首字节的内容(虚函数表里存储的都是虚函数指针);
(int *)*(int *)(&b):对其进行强制类型转换成(int *)的目的是当对其执行间接访问操作时,可以访问到以该地址开始的连续四个字节的内存空间,因为指针总是要占四个字节的。强制类型转换之后该值表示虚函数指针表中第一个函数指针的地址,
*(int *)*(int *)(&b):第二次解引用。得到虚函数指针表中第一个函数指针,可以调用虚函数。
一般继承(无虚函数覆盖)
有类如下:
对象--->虚函数表地址
按上文所述,派生类对象d的虚函数表如下:
代码中for循环的条件为"i<3"时,可以输出派生类d重载的三个虚函数,说明派生类的f(), g(), h()函数将继承自Base类的这个三个函数覆盖。
注意:但将for循环的条件改为”i<6”时,执行时仍会报读内存错误。(具体原因大家可以自行套论一下)。
结束语
剩下三种情况自行分析,其实指针也就那么回事哦.(流泪。。。)
一般继承(有虚函数覆盖)
多重继承(无虚函数覆盖)
多重继承(有虚函数覆盖)