意外输出...函数绑定如何在虚拟 table 中发生

Unexpected Output...how function binding happens in virtual table

class Base
{

public:
    int a;
    virtual void fun1()
    {
        cout<<"Hello Base"<<endl;
    }

    void fun2()
    {
       fun1();
    }

};

class Derived: public Base
{
    int a;
    void fun1()
    {
        cout<<"Hello Derived"<<endl;
    }

};


int main()
{
    Base * B = new Derived;
    B->fun2();
    return 1;
}   

请帮我理解为什么输出是 Hello Derived.How 这个函数绑定需要 place.How 是虚拟的 table 为 Base 创建的条目和派生的 class.

伪代码如下所示:

#include <iostream>

class Base{
protected:
  void **vt_ptr;
public:

    int a;
    //Executed prior to base member initialization
    //and reexecuted prior to Base destructor call
    void set_dynamic_type(){
      vt_ptr = Base::vtable;
    }

    /*virtual*/
    void fun1(){
       reinterpret_cast<void(*)(Base&)>(vt_ptr[1])(*this);
    }
    void fun2(){
       fun1();
     }

private:
  static void func1_def(Base& pseudo_obj_arg){
        Base* this=&pseudo_obj_arg;
        std::cout<<"Hello Base"<<std::endl;
    }
  static void* vtable[2];
};

void* Base::vtable[2]={
     reinterpret_cast<void*>(&type_id_of_Base),
     reinterpret_cast<void*>(&Base::func1_def)};

class Derived: public Base
{
    int a;
    //Executed after Base intialization, 
    //before Derived member initialization.
    //Reexecuted prior to Derived destructor call
    void set_dynamic_type(){
      Base::vt_ptr = Derived::vtable;
    }


private:
  static void func1_def(Base& pseudo_obj_arg){
      Derived* this=static_cast<Derived*>(&pseudo_obj_arg);
      std::cout<<"Hello Derived"<<std::endl;
  }
  static void* vtable[2];  
};

void* Derived::vtable[2]={
     reinterpret_cast<void*>(&type_id_of_Derived),
     reinterpret_cast<void*>(&Derived::func1_def)};

也是一个合格的调用,如:obj.Base::func1()直接调用Base::func1_def(obj),否则会抛出Base::func1.

中描述的去虚拟化过程

虚拟 table 是在构造 class 对象时创建的。当你构造一个 Derived 对象时,它将首先调用 Base 构造函数(它创建 vtable 并将它自己的 Base::fun1 写入其中。然后 Derived 构造函数运行并用自己的实现 (Derived::fun1).

覆盖 fun1 的 vtable 条目

如果您随后在任何时候(甚至在任何 Base 函数内)调用此类对象实例的 fun1,它将查看 vtable 并调用它在那里找到的任何功能。正如上面所解释的,Derived::fun1 在构造后 Derived 对象的 vtable 中,因此这就是将被调用的对象。您当前处于 Base 函数并不重要,vtable 条目不会更改。

请注意, 构造期间,vtable 未完全设置:如果您要从 [=11= 中调用 fun1 ] 构造函数,你会 调用 Derived::fun1Base::fun1 因为 Derived 还没有替换 vtable 条目。

另请注意,完全指定函数(例如,在 Derived 实例上调用 Base::fun1())不会执行 vtable 查找,而是使用指定的函数。