簡體   English   中英

意外的輸出…函數綁定在虛擬表中如何發生

[英]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。如何進行此函數綁定。如何為Base和派生類創建虛擬表條目。

偽代碼如下所示:

#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中描述的去虛擬化過程。

虛擬表是在構造類對象時創建的。 構造Derived對象時,它將首先調用Base構造函數(它將創建vtable並將其自身寫入Base::fun1 。然后, Derived構造函數將運行並使用其自己的實現覆蓋fun1的vtable條目( Derived::fun1 )。

如果這樣,那么在以后的任何時刻(甚至從任何Base函數中)調用此類對象實例的fun1 ,它都將調查vtable並調用在其中找到的任何函數。 如上所述,構造后,它位於Derived對象的vtable中的Derived::fun1 ,因此將被調用。 無論您當前是否處於Base函數中,vtable條目都不會更改。

請注意, 構建過程中 ,尚未完全建立vtable:如果要從Base構造函數中調用fun1 ,則不會調用Derived::fun1而是Base::fun1因為Derived尚未替換vtable條目。

還要注意,完全指定函數(例如,在Derived實例上調用Base::fun1() )不會執行vtable查找,而是完全使用指定的函數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM