一、虚函数表
父类Shape 子类Circle
父类 Shape
vftable_ptr是一个虚表指针,它指向一个存放该类对象的所有虚函数的地址的表;虚函数表与Shape类的定义同时出现,虚函数表占有一定的空间;假设虚函数表的起始位置为0xCCFF,那么虚表指针的值就是0xCCFF;父类的虚函数表只有一个,通过父类实例化出来的所有对象,他的虚表指针的值都是0xCCFF,以确保他的每一个对象的虚表指针指向自己的虚函数表。
调用的时候找到虚表指针,再通过虚表指针找到虚函数表,再通过位置的偏移找到相应的入口地址,从而找到calcArea()
虚表是一个指针数组,其元素是虚函数的指针,每个元素对应一个虚函数的函数指针。
虚表内的条目,即虚函数指针的赋值发生在编译器的编译阶段,也就是说在代码的编译阶段,虚表就可以构造出来了。
子类Circle
circle没有虚函数,但是他继承了shape类,circle类拥有自己的虚函数表,通过他调用的calcArea()函数是父类的该函数
如果将Circle类改为
那么Circle
执行的是子类的calcArea()
虚析构函数:
前提:执行完子类的析构函数就会执行父类的析构函数
当父类的指针指向子类的对象时,使用父类的指针,通过delete的方式去释放子类的对象,只要能够要实现通过父类的指针执行到子类的析构函数
二、什么时候会执行函数的动态绑定?这需要符合以下三个条件
(1)通过指针来调用函数
(2)指针upcast向上转型(继承类向基类的转换称为upcast)
(3)调用的是虚函数
如果一个函数调用符合以上三个条件,编译器就会把该函数调用编译成动态绑定,其函数的调用过程走的是上述通过虚表的机制。
三、在多态的情况下,虚函数表指针在对象当中所占据的内存位置是每个对象的前四个基本内存单元,后面依次排列的是其他数据成员
其他:c++对于一个数据成员都没有的情况,为了标明它的存在,用一个内存单元去标记他