多重继承时的虚函数表

分析以下一段代码(vs2010编译)

 1 #include<iostream>
 2 using namespace std;
 3 class ba
 4 {
 5 public:
 6     double dd;
 7 };
 8 class bas
 9 {
10 public:
11     double d;
12 };
13 
14 class base1
15 {
16     char u;
17 public:
18     virtual void h(){cout<<"base1"<<endl;}
19     virtual void f(){cout<<"base1"<<endl;}
20 };
21 class base2
22 {
23 public:
24     virtual void k(){cout<<"base2"<<endl;}
25     virtual void g(){cout<<"base2"<<endl;}
26     virtual void f(){cout<<"base2"<<endl;}
27     
28 };
29 
30 class base3
31 {
32 public:
33     virtual void e(){cout<<"base3"<<endl;}
34     virtual void f(){cout<<"base3"<<endl;}
35     virtual void g(){cout<<"base3"<<endl;}
36 };
37 class deri:public ba,public base1,public base2,public bas,public base3
38 {
39     char ch;
40 public:
41     void g(){}
42     virtual void ff(){cout<<"deri ff"<<endl;}
43     void f(){cout<<"deri f"<<endl;}
44     void e(){}
45 };
46 int main()
47 {
48     deri dd;    
49     base1* pb1=&dd; 
50     base2* pb2=&dd;
51     printf("%x\n",*((int*)pb1));
52     cout<<pb1<<endl;
53     cout<<pb2<<endl;
54     return 0;  
55 } 
View Code

deri类的内存分布是这样的:

也就是说,含有虚函数的父类排列在没有虚函数的父类之前。在这两种类的内部,父类的分布是按继承时的声明次序排列的,每个父类的成分都非常完整。这个deri类有三个虚函数表指针,同时注意虚函数指针所带来的内存对齐。

对于每一张虚函数表,虚函数在表中的排列次序是按照类中的声明次序来的。deri类自己新增的虚函数会添加到第一张虚函数表的末尾。

对于至少两个父类均有的虚函数(f(),g()),第一个拥有该虚函数的父类的虚表中填入了函数的地址(&deri::f,&deri::g),之后的表都只是记录一个偏移值,即自身指针减去这个偏移值之后(this-=8  this-=12  this-=4),就可以得到第一个拥有该虚函数的父类的起始地址,然后可以调用相应的虚函数。

最后四行是指明了deri类中虚函数的地址分别所在的表的偏移。

 

posted @ 2016-04-07 11:01  vaevaevae  阅读(1692)  评论(0编辑  收藏  举报