Chinaunix首页 | 论坛 | 博客
  • 博客访问: 74196
  • 博文数量: 23
  • 博客积分: 1410
  • 博客等级: 上尉
  • 技术积分: 250
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-10 15:21
文章分类

全部博文(23)

文章存档

2010年(9)

2009年(4)

2008年(10)

我的朋友

分类:

2008-08-04 14:16:57

关于虚表和虚指针的具体实现方法,最近看到了一个我觉得比较符合逻辑的解释:
 
动态绑定的实现机制(三步)

1.为每一个包含虚函数的类设置一个虚表(VTABLE)
每当创建一个包含有虚函数的类或从包含虚函数的类派生一个类时,编
译器就会为这个创建一个VTABLE。在VTABLE中,编译器放置了这个
类中,或者它的基类中所有已经声明为 virtual 的函数的地址。如果在这
个派生类中没有对基类中声明为 virtual 的函数进行重新定义,编译器就
使用基类的这个虚函数的地址。而且所有VTABLE中虚函数地址的顺序是
完全相同的。

2.初始化虚指针(VPTR)
然后编译器在这个类的各个对象中放置VPTR。VPTR在对象的相同的位置(通常都
在对象的开头)。VPTR必须被初始化为指向相应的VTABLE。

3.为虚函数调用插入代码
当通过基类的指针调用派生类的虚函数时,编译器将在调用处插入相应
的代码,以实现通过VPTR找到VTABLE,并根据VTABLE中存储的正确
的虚函数地址,访问到正确的函数。
 
 
 
为了搞清楚虚指针(VPTR)的具体空间分配情况,做了如下的试验
 
试验一
#include
#include
using namespace std;
class cdoc  
{
  public:
    virtual   void   serialize()  
        {cout<<"cdoc::serialize";} 
    void   func()  
        {serialize();}
  private:
          int a;
          char b[3];  
  
};  
   
   
class cmydoc:public cdoc  
{  
   public:
    virtual   void   serialize()  
        {cout<<"cmydoc::serialize";} 
};
 
int main() 
{
  cout<<"Size of cdoc:"<  cout<<"Size of cmydoc:"< 
  return 0;
}
 
运行的结果为:
Size of cdoc:12
Size of cmydoc:12
 
 
试验二
我们稍加改动,将
class cmydoc:public cdoc  
{  
   public:
    virtual   void   serialize()  
        {cout<<"cmydoc::serialize";} 
};
 
改为:
class cmydoc:virtual public cdoc  
{  
   public:
    virtual   void   serialize()  
        {cout<<"cmydoc::serialize";} 
};
 
运行结果变为:
 
Size of cdoc:12
Size of cmydoc:16
 
试验三
改为:
class cmydoc
{  
   public:
    virtual   void   serialize()  
        {cout<<"cmydoc::serialize";} 
};
 
运行结果变为:
 
Size of cdoc:12
Size of cmydoc:4
 
总结:
1)试验三说明:sizeof某个class代表的是以这个class创建对象时给它分配的真实空间的大小,可以看出在32位机器上面,每个包含虚函数的对象是有一个4个字节的虚指针(VPTR)空间的
2)普通继承下,试验一表明每个包含虚函数的对象只有一个指向该类虚表的指针,并不继承父类的虚指针
3)虚继承下,试验二表明实现虚继承时,会需要额外的空间的,要跟虚函数实现的多态的空间分配区分开来
 
阅读(720) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~