概述
OOP或者OOD的概念中,包含有复合composition,委托delegation和继承inheritance三种关系。其中最复杂的就是inheritance。
继承时,子类Derived Class继承的是:
- 父类Base Class的所有数据
- 父类所有函数的调用权
体现inheritance精髓的就是多态了。
这里有几个概念基本是等效的 多态 = 虚函数 = 动态绑定
函数的调用方式
在汇编语言中,函数的调用是通过CALL指令实现的。
在C++中,根据CALL指令后面的参数,函数的调用分为动态绑定和静态绑定两种。
静态绑定
普通的函数,在编译链接后,就确定了其调用地址。所谓静态绑定,就是函数的地址是在链接阶段确定了,无需等到运行时重新计算。
体现为 call address_xxx
的形式
动态绑定
动态绑定则是在运行时才确定函数的调用地址。在C++中,虚函数的调用就是通过这种方式实现的。
动态绑定的条件
- 通过指针进行调用
- 指针是up cast的,即声明时是按照父类Base Class,但new的时候是子类Derived Class的对象
- 调用的是虚函数
多态的用法
动态绑定技术也被称为多态,即一种函数名称(虚函数名),多种形态(虚函数的实体由不同的子类实现)。
典型的用法是,通过将同一各基类的不同子类的指针放到一组容器中,容器以基类指针为类型,通过指针调用不同子类的虚函数的实现
C++中多态的实现
C++在实现多态时,使用了虚指针vptr+虚表vtable的方式。
- 若类中存在1…n个的虚函数,则类的对象的内存空间中存在一个虚指针vptr指向一个虚表vtbl
- 虚表vtbl由该类所有虚函数的函数地址构成,存放类中所有虚函数的指针
- 若父类的虚函数未被重写override,则该虚函数地址为父类虚函数地址
- 若父类的虚函数被重写override,则该虚函数地址为子类虚函数地址
- 子类中的虚表的虚函数的顺序严格与父类一致,以利于通过动态绑定的方式进行寻址
- 最后一个表元素为0
动态绑定的调用方式
p为指向对象的指针,最终动态绑定的虚函数被编译为 (*(p->vptr)[n])§;
最后的§表示p作为this指针被传入。
参考
侯捷老师的C++程序设计(II)