解析动态联编(下篇) - 作者:tingya

2016-01-29 12:18 4 1 收藏

解析动态联编(下篇) - 作者:tingya,解析动态联编(下篇) - 作者:tingya

【 tulaoshi.com - C语言心得技巧 】


解析动态联编(下篇)
作者:南京邮政局计算机中心 tingya
上接解析动态联编(上篇)

三 虚函数表VTABLE

动态联编过程跟我们猜测的大致相同。编译器在执行过程中遇到virtual关键字的时候,将自动安装动态联编需要的机制,首先为这些包含virtual函数的类(注意不是类的实例)--即使是祖先类包含虚函数而本身没有--建立一张虚拟函数表VTABLE。在这些虚拟函数表中,编译器将依次按照函数声明次序放置类的特定虚函数的地址。同时在每个带有虚函数的类中放置一个称之为vpointer的指针,简称vptr,这个指针指向这个类的VTABLE。
关于虚拟函数表,有几点必须声明清楚:
1. 每一个类别只能有一个虚拟函数表,如果该类没有虚拟函数,则不存在虚拟函数表。
2. C++编译时候编译器会在含有虚函数的类中加上一个指向虚拟函数表的指针vptr。
3. 从一个类别诞生的每一个对象,将获取该类别中的vptr指针,这个指针同样指向类的VTABLE。

因此类、对象、VTABLE的层次结构可以用下图表示。其中X类和Y类的对象的指针 都指向了X,Y的虚拟函数表,同时X,Y类自身也包含了指向虚拟函数的指针。

为了方便问题说明,我们将2.cpp例子进行扩展,扩展程序如下。
//4.cpp15. #include <iostream.h 16. class shape{17.  public:18.    virtual void draw(){cout<<"shape::draw()"<<endl;}19.    virtual void area(){cout<<"shape::area()"<<endl;}20.    void fun(){draw();area();}21. };22. class circle:public shape{23.  public:24.    void draw(){cout<<"circle::draw()"<<endl;}25.    void adjust(){cout<<"circle::adjust()"<<endl;}26. };27. main(){28.    shape oneshape;29.    oneshape.fun();30.    31.    circle  circleshape;32.    shape&  baseshape=circleshape;33.    baseshape.fun();34. }
编译器在编译上面这段代码的时候将为这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()方法。如图四。

来源:http://www.tulaoshi.com/n/20160129/1485504.html

延伸阅读
标签: 孕期
补钙专区 补钙的食物有哪些     很多人都会通过服用补钙品来进行补钙,常常忽略了日常饮食中钙质的吸收。补钙食物和补钙食品都是通过食物进行补钙的方法,只要每日可以定量的摄取含钙元素高的食物,就可以有效的调理身体,也可以有效的防止缺钙引发骨质疏松等疾病。那么,在日常生活中有哪些食物可供...
标签: 月子
大姨妈or排卵期 谁决定谁?     排卵是备孕女性必须具备的条件之一,但是月经,却不是受孕最为充分的条件。意思就是说,若是女性没有出现排卵的现象,就算每个的月经按时的来临也不能受孕。那大姨妈or排卵期之间到时寻在这什么关系呢?下面一起去了解下!     一、有月经不一定有...
奶妈酱逆袭《英雄联萌》新阵型培养攻略 哈哈哈,《英雄联萌》最新更新阵型系统三阵型齐发,当年那些个一心只培养输出英雄的大神们如今都傻眼了吧!当年秒我一时爽,如今看你怎么狂!小编我悉心调教多年的星妈酱终于要大放异彩了啊有木有!生命阵型升级血量噌噌往上涨啊有木有!秒不掉我就大奶跟你...
标签: 生活常识
双联开关的工作原理-双联开关的简介 双联开关的简介 双联开关有分为双联单控开关和双联双控开关。单联指一个按钮,单控:就是说它只有一个触点(常开触点或常闭触点)。双控:就是说它有两个触点(常开触点和常闭触点)。这些开关都是指按钮,带弹簧的那种。单联单控开关一般用于点动控制,双联单控开关一般用于长动控制。 ...
《联萌战记》教你如何快速升级 1-15级 新手阶段 尽快做完新手任务,升到16级(前期送的双倍经验卡尽量留着) 15-30级 快速升级阶段 优先做主线任务,直到打不过为止;主线任务奖励大量的金币和经验,还有道具奖励 再做日常任务、周常任务;金币和经验奖励丰厚,竞技...