如何在c ++中决定虚拟表中的索引?

时间:2016-03-08 06:02:37

标签: c++ compilation polymorphism virtual-functions vtable

考虑以下代码。

  #include<iostream>

using namespace std;

class Base
{
public:
    virtual void function1() {cout<<"Base:function1()\n";};
    virtual void function2() {cout<<"Base:function1()\n";};
};

class D1: public Base
{
public:
    virtual void function1() {cout<<"D1:function1()\n";};
    virtual void function2() {cout<<"D1:function2()\n";};
};


int main()
{
    Base *ptr= new D1;

    ptr->function1();
    ptr->function2();

    return 0;
}

ptr将指向D1 obj。 因此,每当我调用ptr-&gt; function1()时,函数地址都从类D1的虚拟表中获取。对于ptr-&gt; function2()也是如此。

在这种情况下,vtable [0]将具有指向function1()的函数指针,vtable [1]将具有指向function2()的函数指针。

我的问题是如何调用函数调用vtable索引映射?

ptr-&gt; function1()&amp; ptr-&gt; function2()索引到vtable [0]&amp; vtable [1]分别?

2 个答案:

答案 0 :(得分:1)

  
    

&#34;计算机科学中的所有问题都可以通过另一层次的间接来解决&#34;

  

我提到了优秀和细节blog post,并在下面尝试解释使用vtable作为您的简单示例。看看你是否通过它阅读。

'Type.one.name' => 'in:A,B,C,D'

在内部,这是编译器遵循的逻辑,以实现虚函数的正确行为。

struct Base;
// enumerates all virtual functions of A    
struct table_Base {
  void (*function1)(struct Base *this);
  void (*function2)(struct Base *this);
};

struct Base {
  const struct table_Base *pvtable; // table maintains pointers to virtual functions. Eventually to implementations
  int data;
};

void Base_function1(struct Base *this) {
  std::cout << "Base:function1()" << std::endl;
}

void Base_function2(struct Base *this) {
  std::cout << "Base:function2()" << std::endl;
}

// table data for Base
static const struct table_Base table_Base_for_Base = { Base_function1,  Base_function2};

void Base_Ctor(struct Base *this) {      
  this->pvtable = &table_Base_for_Base;
  this->data = 1;  
}

// Now for class D1
struct D1;    
struct table_D1 {
  void (*function1)(struct D1 *this);
  void (*function2)(struct D1 *this);
};

struct D1 {
  struct Base base;
  const struct table_D1 *pvtable;
  int more_data;
};

void D1_function1(struct D1 *this) {
  std::cout << "D1:function1()" << std::endl;
}

void D1_function2(struct D1 *this) {
  std::cout << "D1:function2()" << std::endl;
}

// Important functions that do re-direction
void D1Base_function1(struct Base *this) {
  D1_function1((struct D1*) this);
}

void D1Base_function2(struct Base *this) {
  D1_function2((struct D1*) this);
}

// table data for D1
static const struct table_D1 table_D1_for_D1 = {D1_function1,  D1_function2};

// IMPORTANT table
static const struct table_Base table_Base_for_D1 = {D1Base_function1,  D1Base_function2};

// Constructor for derived class D1
void D1_Ctor(struct D1 *this) 
{  
  Base_Ctor(&this->base); // Base class vtable is initialized.

  // Now, Override virtual function pointers   
  this->base.vtbl = &table_Base_for_D1; // Replace the vtable
  this->mode_data = 100;  
}

您可以使用解释的vtable逻辑跟踪上面的方法调用,看看它是否有效。

答案 1 :(得分:1)

该类的第一个元素是usuaylly(隐藏)vtable指针 - vptr。对于多态类,首先将vtable初始化为基类构造函数中的基类的vtable。然后,当派生类构造函数执行相同的vtable指针时,初始化指向派生类vtable。请注意,基类vtable指向function1和function2的基本版本,而派生类vtable指向function1和function2的派生版本。 现在,当指向基类的指针指向派生类的实例时,这通常可能是&#39;发生:

class base
{
    //int* vptr;            //hidden vtable pointer, created by compiler for polymorphic class. vptr points to base class vtable for base clas objects
public:
    virtual void function1(){std::cout <<"base::function1()"<<std::endl;}
    virtual void function2(){std::cout <<"base::function2()"<<std::endl;}
};

class derived: public base
{
    //int* vptr;            //hidden vtable pointer, inherited from the base class. vptr points to derived class vtable for derived class objects
public:
    virtual void function1(){std::cout <<"derived::function1()"<<std::endl;}
    virtual void function2(){std::cout <<"derived::function2()"<<std::endl;}
};


int main()
{
    typedef void (*vtableFnPtr)();      

    base* pBase;
    base base_obj;
    derived derived_obj;

    pBase = &derived_obj;                   //base pointer pointing to derived object

    //one of the several possible implementations by compiler
    int* vtableCallBack = *(int**)&derived_obj; //read the address of vtable pointed by the hidden vptr in the derived_obj

    //pBase->function1();
    ((vtableFnPtr)vtableCallBack[0])();     //calls derived::function1(), when application calls pBase->function1();

    //pBase->function2();
    ((vtableFnPtr)vtableCallBack[1])();     //calls derived::function2(), when application calls pBase->function2();

    pBase = &base_obj;

    //one of the several possible implementations by compiler
    vtableCallBack = *(int**)&base_obj;     //base pointer pointing to base object

    //pBase->function1();
    ((vtableFnPtr)vtableCallBack[0])();     //calls base::function1(), when application calls pBase->function1();

    //pBase->function2();
    ((vtableFnPtr)vtableCallBack[1])();     //calls base::function2(), when application calls pBase->function2();

}

请注意,C ++编译器没有说明用于实现多态行为的实现方法,因此只要行为是多态的,它就完全由编译器来使用vtable或任何其他实现。但是,vtable仍然是实现多态行为的最广泛使用的方法之一。