Thursday, April 22, 2010

vtable - virtual table in C++

What is vtable and how it works.

A virtual method table, virtual function table, dispatch table, or vtable, is a mechanism used in a programming language to support dynamic dispatch (or run-time method binding).It is an array of pointers to virtual functions.

Example:
class BaseClass
{
public:
     
virtual void fun1()
      {
            cout <<
"BaseClass::fun1" << endl;
      }
     
virtual void fun2()
      {
            cout <<
"BaseClass::fun1" << endl;
      }
};
class Derived:public BaseClass
{
     
virtual void fun1()
      {
            cout <<
"Derived::fun1" << endl;
      }
     
virtual void fun3()
      {
            cout <<
"Derived::fun3" << endl;
      }
};
int main()
{
     
//Initialize vtable of BaseClass and copied to pBaseClass's vtable
      //Here Vtavle will contains
      ////BaseClass::fun1()
      ////BaseClass::fun2()
      BaseClass* pBaseClass = new BaseClass();

      pBaseClass->fun1();
//calls BaseClass::fun1()

     
//Initialize vtable of Derived and copied to pDerived's vtable
      //Here Vtavle will contains
      ////Derived::fun1()
      ////BaseClass::fun2()
      ////Derived::fun3()
      Derived* pDerived = new Derived();

     
//vtable value will be replaced with Derived class's vtavle.
      //Here Vtavle will contains

      ////Derived::fun1()
      ////BaseClass::fun2()
      ////Derived::fun3()
      pBaseClass = pDerived;
      pBaseClass->fun1();
//calls Derived::fun1()

Use of __declspec(novtable)

The __declspec stops the compiler from generating code to initialize the vfptr in the constructor(s) and destructor of the class.

Note that in class size will never change and there will be vtable ,but only initializing vtable will never occure. Using this form of __declspec can result in a significant reduction in code size( because of the removal of initialization and de initialization code)

Example:
class A1
{
public:
     
virtual void VirtualFun()
      {
      }
     
void NonVirtualFun()
      {
      }
};
class __declspec(novtable) A2
{
public:
     
virtual void VirtualFun()
      {
      }
     
void NonVirtualFun()
      {
      }
};
int main()
{
     
int sizeA1 = sizeof( A1);//Size will be 4
      int sizeA2 = sizeof( A2);//Size will be 4- no change in size

      A1* a1 =
new A1();
      A2* a2 =
new A2();

      a1->NonVirtualFun();
      a1->VirtualFun();

      a2->NonVirtualFun();
      a2->VirtualFun();
//It will crash.
}

Where we use __declspec(novtable)

If a class has all its virtual functions are pure virtual functions we can use  __declspec(novtable).

Example:
class __declspec(novtable) A2
{
public:
     
virtual void VirtualFun1() = 0;
     
virtual void VirtualFun2() = 0;
     
void NonVirtualFun()
      {
      }
};

What will be output of the following problem?

class BaseClass
{
public:
     
virtual void fun1()
      {
            cout <<
"BaseClass::fun1" << endl;
      }
};
class __declspec(novtable) Derived:public BaseClass
{
     
virtual void fun1()
      {
            cout <<
"Derived::fun1" << endl;
      }
};
int main()
{
      BaseClass *pBaseClass =
new Derived();
      pBaseClass->fun1();
//It will call the BaseClass::fun1();
}

Is it possible to access vtable and its entry.

Sure see the following code.
typedef void (*Fun)(void);
int main()
{
      BaseClass* pBaseClass =
new BaseClass();
      Derived* pDerived =
new Derived();

     
int* pVitrualTablePointer = (int*)(pBaseClass);//Pointer to vtable
      int* pVirtualTable = (int*)*pVitrualTablePointer;//vtable.
      int* pFunctionPointer = (int*)pVirtualTable[0];//First virtual method ie BaseClass::Fun1();

      Fun fun1 = (Fun)pFunctionPointer;
      fun1();
//calls BaseClass::Fun1();

}
With the help of a function.
int* GetVirtualFunction( void* pClassObj,int nMethodIndex)
{
     
return (int*) *((int*)*(int*)((int*)pClassObj)+nMethodIndex);
}
int main()
{
      BaseClass* pBaseClass =
new BaseClass();
      Derived* pDerived =
new Derived();

      Fun fun1 = (Fun)GetVirtualFunction(pBaseClass,0);
      Fun fun2 = (Fun)GetVirtualFunction(pBaseClass,1);

      fun1();
//calls BaseClass::Fun1();
      fun2();//calls BaseClass::Fun1();
      fun1 = (Fun)GetVirtualFunction(pDerived,0);
      fun2 = (Fun)GetVirtualFunction(pDerived,1);
      Fun fun3 = (Fun)GetVirtualFunction(pDerived,2);

      fun1();
//calls Derived::Fun1();
      fun2();//calls BaseClass::Fun1();
      fun3();//calls Derived::Fun3();
}

 

No comments: