1.多态:指不同的对象收到相同消息时会执行不同的操作也即“一个接口,多个实现”。多态性的实现是通过指向基类的指针或引用访问派生类中同名覆盖的函数。通过虚函数可以实现多态性。
2.虚函数:指向基类的指针或引用在操作它的多态对象时,会根据不同的类对象,调用其相应的函数,这个函数就是虚函数。
3.虚函数实现多态性:在虚函数的类中有一个一维的虚函数表叫做虚表。类的对象有一个指向虚表开始的虚指针。虚表(vtbl)是和类对应的,虚表指针(vptr)是和对象对应的。
编译器在编译的时候,发现Base类中有虚函数,此时编译器会为每个包含虚函数的类创建一个虚表,该表是一个一维数组,在这个数组中存放每个虚函数的地址。
虚表的定位:编辑器为每个类的对象提供了一个虚表指针,这个指针指向了对象所属的虚表。在程序运行时,根据对象的类型去初始化vptr,从而让vptr正确的指向所属类的虚表,所以在调用虚函数时能够找到正确的函数。在构造函数中进行虚表的创建和虚表指针的初始化。
虚表存放在类定义模块的数据段中,模块的数据段通常存放在该模块的全局数据和静态数据中,这样我们可以把虚表看作是模块的全局函数或者是静态数据。虚表是同一个类的对象共享的,但是虚表指针并不是,类的每一个对象都有属于它自己的虚表指针,相当于虚表是公有的,虚表指针是私有的。
4.虚函数表的实现:虚函数表在编译的时候就确定了,而类对象的指针vptr是在运行阶段确定的(动态绑定)
这是实现多态的关键。每当创建一个包含虚函数的类或从包含虚函数的类派生一个类时,编译器就为这个类创建一个vtbl。所有基类和它的子类的虚函数地址(子类自己定义的虚函数除外)在vtbl中存储的位置总是相同的。
虚表中的内容按下面四个原则排列:1、虚函数按照其声明顺序放于表中;2、父类的虚函数在子类的虚函数前面;3、覆盖的函数被放到了虚表中原来父类虚函数的位置;4、没有被覆盖的函数依旧。