c++是如何实现多继承带来的多态问题?

波波桑


多态是指同样的消息被不同类型的对象接收时导致完全不同的的行为。有虚函数的类才能叫多态类型的类,可以从探索虚函数是如何实现动态绑定的来了解如何实现多继承中的多态。

单继承时虚函数动态绑定的实现原理

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

如下图所示:

由上图可以看到基类Base有f(),g()函数,派生类还有新增的h()函数,那么这种单继承的虚函数实现动态绑定的方式是这样的:

从这张超大图片可以看到,每个Base对象都有一个指向Base的虚表的指针,虚表存放着指向每个函数的指针,这些指针存放着对应函数的地址,这样通过虚表指针就能找到虚表,通过虚表就能找到函数指针,通过函数指针就能找到函数,这样虚函数的动态绑定就完成了。派生类Base2也一样。

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

在多继承时,情况会变得更加复杂,因为在多继承时,情况会更加复杂,因为每个基类都有各自的虚函数,这样继承了多个基类的派生类需要多个虚表(或一个虚表分为多段,每个基类的虚表指针指向其中一段的地址。因为有些编译器把多个虚表连成一个)如图所示:

派生类Base3公有继承了Base,Base2,那么虚函数动态绑定的实现方式是这样的:

提示:多重继承时,派生类新增的成员放在第一个表,比如上图Base3()的虚表的m()指针。

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

以上就是我的回答,有不同意见的欢迎来讨论,喜欢我的回答请关注,我们一起学习。


分享到:


相關文章: