在上一篇博客中https://blog.csdn.net/Jochebed666/article/details/86596585说明了多态,那么多态的底层原理是什么呢???
他与虚函数有没有关联???
虚函数的工作原理
C++规定了虚函数的行为,但将实现方法留给了编译器作者。 不需要知道实现方法就可以使用虚函数。但了解虚函数的工作原理有助于更好地理解概念,因此,这里对其进行介绍。
通常,编译器处理虚函数的方法是:给每个对象添加一个隐藏成员。隐藏成员中保存了一个指向函数地址数组的指针。这种数组称为虚函数表 (virtual function table, vtbl)。虚函数表中存储了为类对象进行声明的虚函数的地址。例如,基类对象包含一个指针,该指针指向基类中所有虚函数的地址表。派生类对象将包含一个指向独立地址表的指针。如果派生类提供了虚函数的新定义,该虚函数表将保存新函数的地址:如果派生类没有重新定义虚函数,该虚函数表将保存函数原始版本的地址。如果派生类定义了新的虚函数,则该函数的地址也将被添加到虚函数表中。注意,无论类中包含的虚函数是1个还是10个,都只需要在对象中添加1个地址成员,只是表的大小不同而已。
------摘自《C++ Primer Plus》
通过以上我们总结出如下几点:
- 派生类对象中也有一个虚表指针,派生类对象由两部分构成,一部分是父类继承下来的成员,虚表指针也就是存在部分的另一部分是自己的成员。
- 基类对象和派生类对象虚函数表是不一样的,派生类对象的虚表中存的是重写的派生类虚函数,所以虚函数的重写也叫作覆盖,覆盖就是指虚表中虚函数的覆盖。重写是语法的叫法,覆盖是原理层的叫法。
- 虚函数表本质是一个存虚函数指针的指针数组,这个数组最后面放了一个nullptr。
- 总结一下派生类的虚函数表生成:a.先将基类中的虚函数表内容拷贝一份到派生类虚函数表中 b.如果派生类重写了基类中某个虚函数,用派生类自己的虚函数覆盖虚表中基类的虚函数 c.派生类自己新增加的虚函数按其在派生类中的声明次序增加到派生类虚表的最后。
- 注意:虚函数表存的是虚函数指针,不是虚函数,虚函数和普通函数一样的,都是存在代码段的,只是他的指针又存到了虚表中。另外对象中存的不是虚表,存的是虚表指针。虚表存在代码段/常量区。
那么多态的原理是什么???
虚函数表建立在编一阶段,当运行时通过对象去调虚函数表指针,虚函数表指针指向虚函数表,虚函数表中存放虚函数指针,这样就可以去调对应的函数了,因为上面我们说了虚函数表生成问题,知道对象不同,对应的虚函数表里的虚函数不同,这样就实现出了不同对象去完成同一行为时,展现出不同的形态。
即要达到多态,有两个条件,一个是虚函数覆盖,一个是对象的指针或引用调用虚函数。