卓航论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 162|回复: 2
打印 上一主题 下一主题

解析动态联编(下篇)

[复制链接]
[至尊红钻5级]发帖数量≥8000篇 [未点亮至尊黄钻]威望不足10点 [未点亮至尊蓝钻]在线时间不足10小时 [未点亮至尊绿钻]贡献度不足10点 [至尊紫钻4级]金币≥20000个 [未点亮至尊粉钻]精华贴数不足10贴 [未点亮至尊黑钻]活跃不足8个
 等级: 
 级别: 论坛元老
 UID:  7   [未点亮普号显示]钻石不足3个
 阁 分: 36567
 阁 望: 0
 阁 献: 0
 活 跃: 0
 发 贴: 12405 (0)
 阁 币: 24162  
性 别: I'm 火星人!
阅读权限: 90
在线时长: 0 小时
注册时间: 2016-10-16
最后登录: 2016-10-18
go
楼主
发表于 2016-10-17 16:25:24 |只看该作者 |倒序浏览
本帖发表于 2016-10-17 16:25:24...阅读 163 人...加油,亲爱的楼主:[db:作者]
三 虚函数表VTABLE
动态联编过程跟我们猜测的大致相同。编译器在执 行过程中遇到virtual关键字的时候,将自动安装动态联编需要的机制,首先为这 些包含virtual函数的类(注意不是类的实例)--即使是祖先类包含虚函数而本身 没有--建立一张虚拟函数表VTABLE。在这些虚拟函数表中,编译器将依次按照函 数声明次序放置类的特定虚函数的地址。同时在每个带有虚函数的类中放置一个 称之为vpointer的指针,简称vptr,这个指针指向这个类的VTABLE。
关于 虚拟函数表,有几点必须声明清楚:
1. 每一个类别只能有一个虚拟函数 表,如果该类没有虚拟函数,则不存在虚拟函数表。
2. C++编译时候编译 器会在含有虚函数的类中加上一个指向虚拟函数表的指针vptr。
3. 从一 个类别诞生的每一个对象,将获取该类别中的vptr指针,这个指针同样指向类的 VTABLE。
因此类、对象、VTABLE的层次结构可以用下图表示。其中X类和Y 类的对象的指针 都指向了X,Y的虚拟函数表,同时X,Y类自身也包含了指向虚拟函 数的指针。

为了方 便问题说明,我们将2.cpp例子进行扩展,扩展程序如下。//4.cpp
15. #include
16. class shape{
17.  public:
18.  virtual void draw(){cout
编译器在编译上面这段代码的时候将为这shape和circle两个对象 分别建立一个VTABLE表,这些表依次填充派生类对象和基类对象中声明的所有的 虚函数地址。如果派生类本身没有重新定义基类的虚函数,那么填充的就是基类 的虚函数地址。这样一旦如果函数调用一个派生类不存在的方法时候能够自动调 用基类方法。然后编译器在每个类中放置一个vptr,一般置于对象的起始位置, 继而在对象的构造函数中将vptr初始化为本类的VTABLE的地址。整个结果布局如 下。

图一
               
图一中的rectangle的VTABLE中的area() 和triangle的VTABLE的adjust() 都是填充的基类的虚函数地址。 C++ 编译程序时候按下面的步骤进行工 作:
①为各类建立虚拟函数表,如果没有虚函数则不建立。
②暂时 不连接虚函数,而是将各个虚函数的地址放入虚拟函数表中。
③直接连接 各静态函数。
这些工作做完之后,模块图如图二:

图二
执行时候,诞生了oneshape和circleshape两个对象,oneshape对象的 vptr指针指向shape的VTABLE,circleshape对象的vptr指针指向circleshape的 VTABLE,在执行oneshape.fun()的时候,fun函数的this指针指向了oneshape对象 ,进入fun()之后程序继续执行this->draw(),由于this指向oneshape对象, oneshape的vptr又指向shape类的VTABLE,这样就从VTABLE中得到需要绑定的函数 的地址,并连接起来。同样,this-> area()也经由oneshape对象而连接到相 应的函数上,如图三。

图三
               
现在我们执行baseshape.fun()函数。
circle  circleshape;
shape& baseshape=circleshape;
baseshape.fun();
函数进入fun函数之后,函数的this指针将指向 basefun对象,另一方面basefun指向一个circleshape,因此this指针指向的实际 上为circleshape对象,而circleshape的vptr指针指向circle类的虚拟函数表, 这样编译器将从虚拟表中取出circle::draw()和circle::area()的地址,进行连 接。因为circle本身没有重新定义area()方法,因此编译器使用shape的area()方 法。如图四。

图四
遵循上面的思路,基于基类的指针总能找到正确的子类对象的实现。但是 象上面的 this->draw是怎么编译的呢。
               
四 编译内幕
在上面的 程序中,this指针不同,从而连接到不同的fun函数。那么C++如何编译这些指令 呢。道理在于:所有的基类的派生类的虚拟函数表的顺序与基类的顺序是一样的 ,对于基类中不存在方法再按照声明次序进行排放。这样不管是shape还是circle 或者从shape又继承出来的其余的类它们的虚拟函数表的第一项总是draw函数的地 址,然后是area的地址。对于circle类,下面的才是adjust的地址。因此不管对 于shape还是circle,this->draw总是编译成 call this->VTABLE[0]; this->area()总是翻译成 call this->VTABLE[1]; 程序到真正运行时候将 会发现this的真正指向的对象,如果是shape,则调用shape->VTABLE[0],如果 是circle,则调用circle->VTABLE[1],如图五。

图五
请看下面的这个例子。
35. #include
36. class shape{
37. public:
38.  virtual void draw() {coutadjust();//错误,编译器无法通过
52.
53.   circle* circleshape;
54.  circleshape->adjust();
55. }
在程序编译期间,由于oneshape为shape类型的,因此它将检查shape 的虚拟函数表,发现VTABLE[0]为draw函数的地址,于是翻译成p->VTABLE[0] 。未来执行期间,p 实际上指向的是circle对象,因此真正调用的为circle- >VTABLE[0]处的函数,即circle::draw。同样对于adjust函数,C++ 编译器也 会去检查shape的VTABLE,结果编译器无法找到adjust函数,因此编译无法通过。 对于circleshape,因为它是circleshape类型的,因此它将会检查circle的 VTABLE,得知VTABLE[2]处为adjust的地址,因此编译器翻译成call circleshape ->VTABLE[2],真正执行时候circleshape为circle类型,因此它将绑定circle 的VTABLE[2]处的函数即circle:: adjust()。 就这样,编译器借助虚拟函数表实 现了动态联编的过程,从而使多态的实现有了可能。因此说虚拟函数表是多态性 的幕后功臣一点也不为过。
五 结束语
多态性的实现是一个非常复 杂的过程,上面的讨论仅仅是针对简单继承而言,即基类只有一个的情况,对于 多重继承,情况又会有所改变。本文仅是抛砖引玉,希望有兴趣的朋友可以一起 探讨。
分享到: QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏0 支持支持0 反对反对0

使用道具 举报

[至尊红钻3级]发帖数量≥1000篇 [未点亮至尊黄钻]威望不足10点 [未点亮至尊蓝钻]在线时间不足10小时 [未点亮至尊绿钻]贡献度不足10点 [未点亮至尊紫钻]金币不足100个 [未点亮至尊粉钻]精华贴数不足10贴 [未点亮至尊黑钻]活跃不足8个
 等级: 
 级别: 金牌会员
 UID:  2   [未点亮普号显示]钻石不足3个
 阁 分: 1290
 阁 望: 0
 阁 献: 0
 活 跃: 0
 发 贴: 1285 (0)
 阁 币: 5  
性 别: I'm 火星人!
阅读权限: 70
在线时长: 0 小时
注册时间: 2016-10-14
最后登录: 2016-10-18
沙发
发表于 2016-10-18 11:03:18 |只看该作者
本回复帖发表于 2016-10-18 11:03:18,感谢hjghjgj对本帖的认真回复,你的回复是对楼主莫大的鼓舞
写的真的很不错

使用道具 举报

[至尊红钻2级]发帖数量≥100篇 [未点亮至尊黄钻]威望不足10点 [未点亮至尊蓝钻]在线时间不足10小时 [未点亮至尊绿钻]贡献度不足10点 [未点亮至尊紫钻]金币不足100个 [未点亮至尊粉钻]精华贴数不足10贴 [未点亮至尊黑钻]活跃不足8个
 等级: 
 级别: 注册会员
 UID:  29   [未点亮普号显示]钻石不足3个
 阁 分: 111
 阁 望: 1
 阁 献: 4
 活 跃: 0
 发 贴: 104 (0)
 阁 币: 1  
性 别: I'm 火星人!
阅读权限: 20
在线时长: 2 小时
注册时间: 2011-1-6
最后登录: 2016-10-20
板凳
发表于 2016-10-19 20:19:11 |只看该作者
本回复帖发表于 2016-10-19 20:19:11,感谢za402对本帖的认真回复,你的回复是对楼主莫大的鼓舞
没看完~~~~~~ 先顶,好同志

使用道具 举报

高级模式
B Color Image Link Quote Code Smilies
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

1、请认真发帖,禁止回复纯表情,纯数字等无意义的内容!帖子内容不要太简单!
2、提倡文明上网,净化网络环境!抵制低俗不良违法有害信息。
3、每个贴内连续回复请勿多余3贴,每个版面回复请勿多余10贴!
4、如果你对主帖作者的帖子不屑一顾的话,请勿回帖。谢谢合作!

手机版| 百度搜索:vkee.pw

2012-2015 卓航旗下 GMT+8, 2024-5-18 20:18 , Processed in 0.566033 second(s), 30 queries . Powered by Discuz! X3.2  

禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.如遇版权问题,请及时联系站长(QQ:5213513)

今天是: | 本站已经安全运行: //这个地方可以改颜色

快速回复 返回顶部 返回列表