0
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.

Ayush Gupta
  • 77
  • 10
  • 1
    If you want `Base::fun2` to call `Base::fun1` then fully qualify it, like I just did in this comment. – Some programmer dude Apr 05 '18 at 11:56
  • 1
    `fun1` is virtual. It doesn't matter where you call it from, it's still virtual. – molbdnilo Apr 05 '18 at 12:01
  • Is this what you are asking? [How are virtual functions and vtable implemented?](https://stackoverflow.com/questions/99297/how-are-virtual-functions-and-vtable-implemented) – Bo Persson Apr 05 '18 at 12:18
  • Please understand the basics of the language and search before posting; both the Standardese and compilerese sides of this are amply answered already. – underscore_d Apr 05 '18 at 12:34
  • The C++ standard does not require use of vtables. It is a common (universal, AFAIK) implementation choice because it offers advantages over alternatives. The requirement in the standard amounts to, when calling a virtual function through a pointer or reference to `Base`, the function corresponding to the ACTUAL type of the object (in this case `Derived::fun1()`) is called. Within `fun2()`, the `this` pointer points at an instance of the most derived type (in this case `Derived`). – Peter Apr 05 '18 at 12:41

2 Answers2

1

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.

Oliv
  • 17,610
  • 1
  • 29
  • 72
1

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 (e.g. calling Base::fun1() on a Derived instance) will not do a vtable lookup but instead use exactly the specified function.

Max Langhof
  • 23,383
  • 5
  • 39
  • 72