背景
C++的三大特性:封装,继承,多态。其中基于多态特性的虚函数表概念是C++开发者面试的长考题。今天梳理一下虚函数表的基本概念。
概念理解
为了实现 C++ 的多态,C++ 使用了一种动态绑定的技术。这个技术的核心是虚函数表。
虚表就是为了实现面向对象的多态而设计的,简单说就是父类指针能调用子类成员函数。实现简单粗暴:把同一个类的所有虚函数地址放到一个指针的数组里,每一个类一个表。另外在每一个对象的结构体中放置一个指向虚表的指针。在调用时,根据对象里的虚表指针找到对应的虚表,再根据调用函数确定虚表中的哪一个函数地址。在构造时,构造函数开头隐藏了一句把虚表指针指向本类的对应的虚表地址。
对应C++多态特性的三个概念:虚函数,虚表,虚表指针。
1)每个包含虚函数的类都有一个虚表,虚表是一个指针数组,指向其对应的虚函数。继承了父类的子类也会有自己对应的虚表。
2)虚表是类的所有对象共有的,即一个类只有一个虚表。
为了指定对象的虚表,对象内部包含一个虚表的指针,来指向自己所使用的虚表。为了让每个包含虚表的类的对象都拥有一个虚表指针,编译器在类中添加了一个指针,*__vptr,用来指向虚表。这样,当类的对象在创建时便拥有了这个指针,且这个指针的值会自动被设置为指向类的虚表。
3)C++通过虚表和虚表指针实现动态绑定。父类对象也可以调用到子类实现的虚函数。
下图中,类B继承类A,类C继承类B。
理解要点:对象的虚表指针用来指向自己所属类的虚表,虚表中的指针会指向其继承的最近的一个类的虚函数 。
如下两种写法,可以让父类A调用到子类B的vfunc1实现和父类A自己本身的vfunc1的实现。
int main()
{
B bObject;
A *p = & bObject;
p->vfunc1(); //print class B's vfunc1
A aObject;
A *p1 = &aObject;
p1->vfunc1(); //print class A's vfunc1
}
4)多态的理解
父类函数有多个子类继承,子类重写了父类的虚函数实现,通过定义父类函数指针指向子类对象的地址,父类就可以调用到子类的虚函数实现方式,这种现象可以理解为多态。
C++虚函数表剖析_c++中的虚函数表-CSDN博客