关于继承以后的虚函数调用有关问题,来瞧瞧
关于继承以后的虚函数调用问题,高手进来瞧瞧
请教一下为何我
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指向地址
#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指向地址