![]() ![]() |
||||||
细谈C++多态性的“动”与“静” | ||||||
作者:佚名 文章来源:不详 点击数 更新时间:2008/4/18 14:38:12 文章录入:杜斌 责任编辑:杜斌 | ||||||
|
||||||
if...else...;switch...case... 这些代码通常都属于硬编码,项目中的这些代码多了,就相当于说明这个代码的灵活性、扩展性、弹性等等的少了。 所以,我们要尽量使用软编码,通俗点就是“别把话说死了,留点转弯的余地”。多态性就是这种软编码特性的反映,下面我们一起来研究一下多态性。 多态性是一种抽象,把事物的特征抽象出来,然后事物的具体形态我们就不关心了。 例如对工人这种事物来说,他的特征就是工作,至于是什么工人,他做什么工作,我们就不用关心了,只要我们以“工人.工作”这种方式去调用。那他就会为我们工作了。 那为什么我们不抽象出其他的特征,只抽象出工作这个特征呢?因为我们只对这个特征感兴趣,他的什么吃饭、睡觉、如厕等的特性我们都不关心了。有了多态,我们就可以实现软编码了! 讲解了多态的概念之后,我们来看看多态的实现(C++的实现): 多态的实现是通过虚函数表(VTable),每个类如果有虚函数,那它就有一个虚函数表,所有的对象都共享这一个VTable。这个概念也叫做动态联编,还有静态联编,这些概念都是通过在程序执行的时候表现出来的性质来定的,我们下面会看看它的“动”和“静”究竟体现在哪里。 先看一段代码:
这个类没有虚函数,调用的时候就是静态调用。调用的代码如下:
它的调用:
根据上述的汇编代码,我们可以知道,在多态调用函数的时候,程序执行以下步骤: 1、寻址找到pObj1 2、由于C11重载了Test虚函数,所以*pObj1指向的就是C11的VTable的地址 3、调用pObj1->Test()时,程序通过Vptr(虚表的指针,对象的首地址),找到VTable,再根据偏移调用Test函数。 由于上述的多态调用过程是一个动态的过程(在运行时去“找”函数来调用),而不是编译完就直接把函数地址摆在那里了,所以被称作“动态联编”。 上面把多态的“动”和“静”的特点结合代码说了一遍,希望能说清楚了。 下面再验证一个类的虚表的问题,如果你对虚表已经很熟悉了,就不用再往下看了。 在很多书上都已经说明了C++的对象模型,这里只是做个验证。看看这段代码:
我们可以知道 Test() 是虚函数,从C1派生的类必定有自己的虚表。而且根据别的资料,虚表指针是放在对象的首地址的,我们下面就来验证一下:
结果是: obj110 的地址:12ff7c obj111 的地址:12ff78 obj110 虚表的地址:432098 obj111 虚表的地址:432098 由上面的结果我们可以验证: 1、一个类一个VTABLE,而不是一个对象一个VTABLE。 2、对象的首地址的内容就是VTABLE的地址。 总结一下: C++的多态性包括其概念和实现,本文从编译器生成的代码来讨论C++多态特性,特别说明了为什么多态特性被称为“动态联编”,它和“静态联编”有什么不同,它们的“动”与“静”体现在哪里。另外还对对象的虚表做了些验证。好了,希望本文能对你认识C++的多态性有一定的帮助! |
||||||
![]() ![]() |