关于继承以后的虚函数调用有关问题,来瞧瞧

关于继承以后的虚函数调用问题,高手进来瞧瞧

#include <iostream>

class a{
public:
virtual void bindobj(void**)=0;
};

class x:public a{
public:
virtual void fx()=0;

};

class y:public a{
public:
virtual void fy()=0;

};

class b: public x,public y{
public:
virtual void bindobj(void **p){
*p = this;
}
private:
virtual void fx(){std::cout <<"fx function has been called"<<std::endl;}
virtual void fy(){std::cout <<"fy function has been called"<<std::endl;}

};

int main()
{

b obj;

x *px;
y *py;

obj.bindobj(reinterpret_cast<void**>(&px));
px->fx();

obj.bindobj(reinterpret_cast<void**>(&py));
py->fy();

system ("pause");
return 0;
}




请教一下为何我
px->fx();
py->fy();
调用结果都显示只调用了fx()函数,而没有调用fy()函数?
而且当我把class b: public x,public y的继承顺序改成class b: public y,public x以后
两次调用的却都是fy()函数,这是为何啊..百思不得其解....

------解决方案--------------------
虚函数的调用是从对象上去找函数指针的.
所以, 对象决定了调用的是哪个函数, 而不是指针的类型.
多继承是, 子类转换成不同的父类的指针是不同的. 不能直接赋值, 要经过转换才行. 而这种转换通常来说, 第一个父类的指针和子类指针是相同的. 第二个父类的指针等于   子类指针 + 第一个父类的大小 


------解决方案--------------------
首先要明白的是类b不是虚继承,故在b类对象中会保留两份从a类继承下来的成员
类x虚函数表示意图
关于继承以后的虚函数调用有关问题,来瞧瞧
类y虚函数表示意图
关于继承以后的虚函数调用有关问题,来瞧瞧
类b存储结构示意图
关于继承以后的虚函数调用有关问题,来瞧瞧

上面的示意图是从调试的汇编代码总结的:
类b构造函数的部分汇编代码:
004012B0   mov         eax,dword ptr [ebp-4]   //eax存放obj对象地址
004012B3   mov         dword ptr [eax],offset b::`vftable' (0042f028)
004012B9   mov         ecx,dword ptr [ebp-4]   //ecx存放obj对象地址
004012BC   mov         dword ptr [ecx+4],offset b::`vftable' (0042f01c)
从上面看出类b的虚函数表被初始化了两次。
第一次初始化指向类x的虚函数表指针,将其存放在 &obj 的位置。
(0042f028处存放x::bindobj函数地址,0042f028+4处存放b::fx函数地址)
第二次初始化指向类y的虚函数表指针,将其存放在 &obj+4 的位置
(0042f01c处存放y::bindobj函数地址,0042f01c+4处存放b::fy函数地址)

执行bingobj后,px和py都指向&obj;
再看看 px->fx() 汇编码:
1,004011DC   mov         ecx,dword ptr [ebp-0Ch] //ecx存放px指向地址
//下面一句汇编码的意思是将内存地址为ecx的内存所存内容赋值给edx
2,004011DF   mov         edx,dword ptr [ecx]     //edx的值为0042f028
3,004011E1   mov         esi,esp
4,004011E3   mov         ecx,dword ptr [ebp-0Ch]  
5,004011E6   call        dword ptr [edx+4] //edx+4为b::fx函数地址

再看看 py->fy() 汇编码
004011FC   mov         ecx,dword ptr [ebp-10h] //ecx存放py指向地址