用派生类的指针调用基类的函数为什么也可以实现多态?该怎么处理

用派生类的指针调用基类的函数为什么也可以实现多态?
C/C++ code
#include<iostream.h>
class A
{
 public:
   virtual void f()
     {cout<<"A::f()"<<endl;}
     void g()
     {cout<<"A::g()"<<endl;}
     void h() 
     {
         cout<<"A::h()"<<endl;
         f(); g(); 
     }
};
class B: public A
{
 public:
    void f()
    {cout<<"B::f()"<<endl;}
    void g()
    {cout<<"B::g()"<<endl;}
};

void main()
{
    B b;
    B * p=&b;
    p->h();

}


结果:
A::h()
B::f()
A::g()

最近在学习C++的虚函数,书上说要用基类的指针或引用才能实现多态。但上述代码,p是子类的,调用派生来的h(),this指针也是指向B类的,this->f()
假如说,只是简单的调用自己的f()(不是通过虚函数)。那么下一句,this->g()也应当是简单的调用自己的g(),输出是B::f()啊。
或者,派生类的指针调用基类的函数,而此函数中又调用虚函数,也可以实现多态(好像就基类的构造函数不可以)。那么就,当调用h()时候,作用域已经变成A::,此函数体中的调用也都是在A::的作用域中,因为有多态,F()调用的是子类中的,而,g()仍在A::中,调用的是A::中的g()。如果这样解释的话应该好些。

于是就很矛盾了,第一次提问,还请大家多多指教,还有没有多少积分,给不了多少,见谅,呵呵 ^^

------解决方案--------------------
正确答案来啦


首先 对象B 有一个虚函数表vftable 保存了 A B继承体系中唯一一个虚函数f,且表中唯一一项也是第一项就是B::f()地址

那么不管用什么指针,只要指向的对象是B的 再调用f函数时就会选择B本身的虚函数表第一项,就是调用B::f 啦


然后 打印A::h() 很明显,B没有重载这个函数,肯定要走入A::h() 查看h方法反汇编如下,
看到下面一行 就知道,再h中嗲用g编译器已经事先写死了 就是调用A的g方法

call A::g (4157FDh) 

综上 疑问解决

Assembly code

        f(); g(); 
00416E41  mov         eax,dword ptr [this] 
00416E44  mov         edx,dword ptr [eax] 
00416E46  mov         esi,esp 
00416E48  mov         ecx,dword ptr [this] 
00416E4B  call        dword ptr [edx] 
00416E4D  cmp         esi,esp 
00416E4F  call        @ILT+2795(__RTC_CheckEsp) (415AF0h) 
00416E54  mov         ecx,dword ptr [this] 
00416E57  call        A::g (4157FDh)

------解决方案--------------------
我说说我的一点理解啊。
当这句 p->h(),派生类指针调用基类函数。此时要进行一个this指针的转换。

p->h()相当于h(this)
此时this是B*;但是h()是A的函数,因此要进行一个指针的转换为this(A*);
转换后h()内部调用调用虚函数f(),即this->f(),因此实现了多态。

其中的指针转换与A *pa=new B一样


------解决方案--------------------
探讨
谢谢 Dinelgua ,回答的很好,呵呵
按照你的观点,是不是指针未被转换成A*(见11楼)?

还有,我还没学过汇编,能问一下,
既然B::继承了h(),h()属于B了,为什么编译器“事先写死”的不是B::g()呢
谢谢了