c++虚函数实现原理 (c++对象里面的虚函数)

昨天我们了解了一种简单、直接的动态绑定的实现方式,但是该处理方式实际在对象中保存了大量的重复信息,例如不同的Derivied类的对象所保存的这3个指针都是一样的——它们都分别指向Derived::f ,Base::g ,和Derived::h 。因此,这些指针都可以只保存一份,它们构成一个表,称为虚表,每个对象中不再保存一个个函数指针,而是只保存一个指向这个这个虚表首地址的指针——虚表指针。这样,每个多态类型的对象只需要占用一个指针的额外空间,虽然虚表本身还要占用空间,但是每一个多态类型只有一个虚表,这一部分空间不会因新对象的创建而有所增加。相应的布局如下图所示:

c++虚函数怎么实现的,c++虚函数如何实现

动态绑定通常的实现方式

每个类各有一个虚表,虚表的内容是由编译器安排的。派生类的虚表中,基类声明的虚函数对应的指针放在前面,派生类新增的虚函数的对应指针放在后面,这样一个虚函数的指针在基类虚表和派生类虚表中具有相同的位置。每个多态类型的对象中都有一个指向当前类型的虚表的指针,该指针在构造函数中被赋值。当通过基类的指针或引用调用一个虚函数时,就可以通过虚表指针找到该对象的虚表,进而找到存放该虚函数的指针的虚表条目。将该条目中存放的指针读出后,就可以获得应当被调用的入口地址,然后调用该虚函数,虚函数的动态绑定就是这样完成的。

补充:执行一个类的构造函数时,首先被执行的是基类的构造函数,因此构造一个派生类的对象时,该对象的虚表指针首先会被指向基类的虚表。只有当基类构造函数执行完成后,虚表指针才会指向派生类的虚表,这就是基类的构造函数调用派生类的虚函数的原因。

c++虚函数怎么实现的,c++虚函数如何实现

在多继承时,情况会更加复杂,因为每个基类都有各自的虚函数,每个基类都有各自的虚函数,每个基类也会有各自的虚表,这样继承了多个基类的派生类需要多个虚表(或一个虚表分为许多段,每个基类的虚表指针指向其中一段的首地址)。

c++虚函数怎么实现的,c++虚函数如何实现

事实上,一个类的虚表中国内存放的不只是虚函数的指针,用于支持运行时类型识别的对象的运行时类型信息也需要通过虚表来访问。只有多态类型有虚表,So只有多态类型支持运行时类型识别。

c++虚函数怎么实现的,c++虚函数如何实现