Welcome

首页 / 软件开发 / C++ / 解析动态联编(下篇)

解析动态联编(下篇)2010-08-19tingya三 虚函数表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 <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的地址。整个结果布局如 下。

图一