C++多态虚函数表详解

转载自:https://blog.csdn.net/qq_36359022/article/details/818702

C++虚函数表是支撑C++多态的重要技术,它是C++动态绑定技术的核心。

一、内存分布

假设有一个基类ClassA,一个继承了该基类的派生类ClassB,并且基类中有虚函数,派生类实现了基类的虚函数。
我们在代码中运用多态这个特性时,通常以两种方式起手:
(1) ClassA *a = new ClassB();
(2) ClassB b; ClassA *a = &b;
以上两种方式都是用基类指针去指向一个派生类实例,区别在于第1个用了new关键字而分配在堆上,第2个分配在栈上。

请看上图,不同两种方式创建方式仅仅影响了派生类对象实例存在的位置。

以左图为例,ClassA *a是一个栈上的指针。该指针指向一个在堆上实例化的子类对象。基类如果存在虚函数,那么在子类对象中,除了成员函数与成员变量外,编译器会自动生成一个指向**该类的虚函数表(这里是类ClassB)**的指针,叫作虚函数表指针。通过虚函数表指针,父类指针即可调用该虚函数表中所有的虚函数。

二、类的虚函数表和类实例的虚表指针

首先在不考虑继承的情况下。如果一个类有虚函数,那么该类就有一个虚函数表,这个虚函数表是属于类的,所有该类的实例化对象都会有一个虚函数表指针指向该类的虚函数表。

从第一部分的图中我们也能看到,一个类的实例要么在堆上,要么在栈上,也就是说一个类可以有很多个实例。但是,一个类只有一个虚函数表。在编译时,一个类的虚函数表就确定了,这也是为什么它放在了只读数据段中

调用的过程如下:

例如:

A* p = new B()

p->func()

实际的调用过程是:

vt = p->vptr;         // 获取虚表

vf = vt[0];          //获取函数地址,因为这里只有一个虚函数,所以fun在虚表中的标号为0

p->vf()

三、普通继承/多重继承下的虚函数表

在有继承情况下,只要基类有虚函数,子类不论实现或没实现,都有虚函数表

子类中与基类虚函数同名的函数,也会自动加上virtual。

首先,子类会继承基类的虚函数表,如果重写了基类的虚函数会更新虚函数表。如果没有重写任何基类的虚函数,那么子类和基类的虚函数表是内容是一致的。

但是,基类的虚函数表和子类的虚函数表不是同一个表。

四、多继承下的虚函数表(同时继承多个基类)

多继承是指一个类同时继承了多个基类,假设这些基类都有虚函数,也就是说每个基类都有虚函数表,那么该子类的逻辑结果和虚函数表是什么样子呢?

在多继承情况下,有多少个基类就有多少个虚函数表指针,前提是基类要有虚函数才算上这个基类。

注意:
1.子类虚函数会覆盖每一个父类的每一个同名虚函数。
2.父类中没有的虚函数而子类有,填入第一个虚函数表中,且用父类指针是不能调用。
3.父类中有的虚函数而子类没有,则不覆盖。仅子类和该父类指针能调用。

 

参考链接:https://zhidao.baidu.com/question/518143717.html

posted @ 2020-04-17 11:04  Rogn  阅读(1833)  评论(0编辑  收藏  举报