C++ 虚函数表研究 (二) 多重继承
上次研究的是单继承的情况,这次研究多重继承下的虚函数表的排列情况。
这次A,A1,A2,B这几个类的继承关系如下图:
各个类的声明如下:
virtual void fun3()
{
cout<<"A::fun3"<<endl;
}
};
class A1:public A
{
public:
virtual void fun1()
{
cout<<"A1::fun1"<<endl;
}
};
class A2:public A
{
public:
virtual void fun2()
{
cout<<"A2::fun2"<<endl;
}
virtual void fun3()
{
cout<<"A2::fun3"<<endl;
}
};
class B :public A1,public A2
{
public:
virtual void fun4()
{
cout<<"B::fun4"<<endl;
}
};
测试代码如下:
cout<<"A1虚函数表的地址为:"<<(int *)(&a1)<<endl;
cout<<"A1第一个虚函数的地址为:"<<(int *) *(int *)(&a1)<<endl;
Fun fun1,fun2,fun3,fun4;
fun1=( Fun) ( *(int *) *(int *)(&a1));
fun1();
fun2=(Fun) (* ((int *) *(int *)(&a1)+1));
fun2();
fun3=(Fun) (* ((int *) *(int *)(&a1)+2));
fun3();
A2 a2;
cout<<"A2虚函数表的地址为:"<<(int *)(&a2)<<endl;
cout<<"A2第一个虚函数的地址为:"<<(int *) *(int *)(&a2)<<endl;
fun1=( Fun) ( *(int *) *(int *)(&a2));
fun1();
fun2=(Fun) (* ((int *) *(int *)(&a2)+1));
fun2();
fun3=(Fun) (* ((int *) *(int *)(&a2)+2));
fun3();
B b;
cout<<"B的第一个虚函数表的地址为:"<<(int *)(&b)<<endl;
cout<<"B的第一个虚函数表的第一个虚函数的地址为:"<<(int *) *(int *)(&b)<<endl;
fun1=( Fun) ( *(int *) *(int *)(&b));
fun1();
fun2=(Fun) (* ((int *) *(int *)(&b)+1));
fun2();
fun3=(Fun) (* ((int *) *(int *)(&b)+2));
fun3();
fun4=(Fun) (* ((int *) *(int *)(&b)+3));
fun4();
cout<<"B的第二个虚函数表的地址为:"<<(int *)(&b)+1<<endl;
cout<<"B的第二个虚函数表的第一个虚函数的地址为:"<<(int *) *((int *)(&b)+1)<<endl;
fun1=( Fun) ( *(int *) *((int *)(&b)+1));
fun1();
fun2=(Fun) (* ((int *) *((int *)(&b)+1)+1));
fun2();
fun3=(Fun) (* ((int *) *((int *)(&b)+1)+2));
fun3();
char ch;
while (1)
{
cin>>ch;
}
return 0;
}
测试代码说明:
A1,A2的虚函数表都是单继承自A,所以跟上一篇的单继承的情况完全相同,这里不再解释。
具体说下B的情况,b分别从A1,A2继承了两个虚函数表,这两个虚函数表也是在对象的开始按照顺序开始排列,先是A1的虚函数表,然后是A2的虚函数表。
B的第一个虚函数表:(int *)(&b)
B的第一个虚函数表的第一个元素fun1= * ((int *) * (int *)(&b))
B的第一个虚函数表的第二个元素fun2= * ((int *) * (int *)(&b)+1)
......
B的第二个虚函数表:(int *)(&b)+1
B的第二个虚函数表的第一个元素 fun1= *
B的第二个虚函数表的第二个元素 fun2= * ((int *) *((int *)(&b)+1)+1)
......
程序运行结果:
A1虚函数表的地址为:0012FF7C
A1第一个虚函数的地址为:0047012C
A1::fun1
A::fun2
A::fun3
A2虚函数表的地址为:0012FF68
A2第一个虚函数的地址为:00470160
A::fun1
A2::fun2
A2::fun3
B的第一个虚函数表的地址为:0012FF60
B的第一个虚函数表的第一个虚函数的地址为:004701A4
A1::fun1
A::fun2
A::fun3
B::fun4
B的第二个虚函数表的地址为:0012FF64
B的第二个虚函数表的第一个虚函数的地址为:00470194
A::fun1
A2::fun2
A2::fun3
结果画成虚函数表如下:
A的虚函数表图:
A1的虚函数表图:
A2的虚函数表图:
B的虚函数表图:
结论:
多重继承会有多个虚函数表,几重继承,就会有几个虚函数表。这些表按照派生的顺序依次排列,如果子类改写了父类的虚函数,那么就会用子类自己的虚函数覆盖虚函数表的相应的位置,如果子类有新的虚函数,那么就添加到第一个虚函数表的末尾。