简体   繁体   中英

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;
}   

Please help me understand why output is Hello Derived.How this function binding takes place.How is virtual table entry created for Base and derived class.

The pseudo code looks like this:

#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)};

Also a qualified call as in: obj.Base::func1() directly calls Base::func1_def(obj) , otherwise it goes throw the devirtualization process described in Base::func1 .

The virtual table is created when the class objects are constructed. When you construct a Derived object, it will first call the Base constructor (which creates the vtable and writes its own Base::fun1 into that. Then the Derived constructor runs and overwrites the vtable entry for fun1 with its own implementation ( Derived::fun1 ).

If you then, at any later point (even from within any Base function) call fun1 of such an object instance, it will look into the vtable and call whatever function it finds there. As explained above, it is Derived::fun1 that is in the vtable of a Derived object after construction, so this is the one that will get called. It doesn't matter that you are currently in a Base function, the vtable entry does not change.

Note that during construction, the vtable is not fully set up: If you were to call fun1 from within the Base constructor, you would not call Derived::fun1 but Base::fun1 because Derived did not replace the vtable entries yet.

Also note that fully specifying the function (eg calling Base::fun1() on a Derived instance) will not do a vtable lookup but instead use exactly the specified function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM