Assumption: 32-bit Machine.
Here I am going to explain How Virtual table, Virtual pointer for Virtual functions are internally working.

First we have understand memory layout.

Example 1: How the class's memory layout
Code: cpp

class Test
{
public:
    int data1;
    int data2;
    int fun1();
};

int main()
{
    Test obj;
    cout << "obj's Size = " << sizeof(obj) << endl;
    cout << "obj 's Address = " << &obj << endl;
    return 0;
}

OUTPUT:

Sobj's Size = 8
obj 's Address = 0012FF7C

Note: Any Plane member function does not take any memory.

Example 2: Memory Layout of Derived class
Code: cpp

class Test
{
public:
    int a;
    int b;
};

class dTest : public Test
{
public:
    int c;
};

int main()
{
    Test obj1;
    cout << "obj1's Size = " << sizeof(obj1) << endl;
    cout << "obj1's Address = " << &obj1 << endl;
    dTest obj2;
    cout << "obj2's Size = "<< sizeof(obj2) << endl;
    cout << "obj2's Address = "<< &obj2 << endl;
    return 0;
}

OUTPUT:
obj1's Size = 8
obj1's Address = 0012FF78
obj2's Size = 12
obj2's Address = 0012FF6C

Example 3: Memory layout If we have one virtual function.
Code: cpp

class Test
{
public:
    int data;
    virtual void fun1()
    {
        cout << "Test::fun1" << endl;
    }
};

int main()
{
    Test obj;
    cout << "obj's Size = " << sizeof(obj) << endl;
    cout << "obj's Address = " << &obj << endl;
    return 0;
}

OUTPUT:

obj's Size = 8
obj's Address = 0012FF7C

Note: Adding one virtual function in a class takes 4 Byte extra.

Example 4: More than one Virtual function

Code: cpp

class Test
{
public:
    int data;
    virtual void fun1() { cout << "Test::fun1" << endl; }
    virtual void fun2() { cout << "Test::fun2" << endl; }
    virtual void fun3() { cout << "Test::fun3" << endl; }
    virtual void fun4() { cout << "Test::fun4" << endl; }
};

int main()
{
    Test obj;
    cout << "obj's Size = " << sizeof(obj) << endl;
    cout << "obj's Address = " << &obj << endl;
    return 0;
}

OUTPUT:

obj's Size = 8
obj's Address = 0012FF7C

Note: Adding more virtual functions in a class, no extra size taking i.e. Only one machine size taking(i.e. 4 byte)

Example 5:

Code: cpp

class Test
{
public:
    int a;
    int b;
    Test(int temp1 = 0, int temp2 = 0)
    {
        a=temp1 ;
        b=temp2 ;
    }
    int getA() 
    {
        return a;
    }
    int getB() 
    {
        return b;
    }
    virtual ~Test();
};

int main()
{
    Test obj(5, 10);

    // Changing a and b
    int* pInt = (int*)&obj;
    *(pInt+0) = 100;   
    *(pInt+1) = 200;   

    cout << "a = " << obj.getA() << endl;
    cout << "b = " << obj.getB() << endl;
    return 0;
}

OUTPUT:
a = 200
b = 10

If we Change the code as then
Code: Cpp


// Changing a and b
int* pInt = (int*)&obj;
*(pInt+1) = 100; // In place of 0
*(pInt+2) = 200; // In place of 1


OUTPUT:
a = 100
b = 200

Note: Who sits 1st place of Class : Answer is VPTR
VPTR - 1st placed in class and rest sits after it.

Example 6:

Code: cpp

class Test
{
    virtual void fun1()
    {
        cout << "Test::fun1" << endl;
    }
};

int main()
{
    Test obj;
    cout << "VPTR's Address " << (int*)(&obj+0) << endl;
    cout << "VPTR's Value " << (int*)*(int*)(&obj+0) << endl;
    return 0;
}

OUTPUT:

VPTR's Address 0012FF7C
VPTR's Value 0046C060

NOTE: This VPTR's value is a address of Virtual table. Lets see in next Example.

Example 7:

Code: cpp

class Test
{
    virtual void fun1()
    {
        cout << "Test::fun1" << endl;
    }
};
typedef void (*Fun)(void);

int main()
{
    Test obj;
    cout << "VPTR's Address " << (int*)(&obj+0) << endl;
    cout << " VIRTUAL TABLE 's Address " << (int*)*(int*)(&obj+0) << endl; // Value of VPTR
    cout << "Value at first entry of VIRTUAL TABLE " << (int*)*(int*)*(int*)(&obj+0) << endl;

    Fun pFun = (Fun)*(int*)*(int*)(&obj+0);   // calling Virtual function
    pFun();
    return 0;
}

OUTPUT:
VPTR's Address 0012FF7C
VIRTUAL TABLE 's Address 0046C0EC
Value at first entry of VIRTUAL TABLE 0040100A
Test: fun1


Example 8:

Code: cpp

class Test
{
    virtual void fun1() { cout << "Test::fun1" << endl; }
    virtual void func1() { cout << "Test::func1" << endl; }
};

int main()
{
    Test obj;

    cout << "VPTR's Address " << (int*)(&obj+0) << endl;
    cout << "VIRTUAL TABLE 's Address"<< (int*)*(int*)(&obj+0) << endl;

    // Calling Virtual table functions
    cout << "Value at 1st entry of VTable " << (int*)*((int*)*(int*)(&obj+0)+0) << endl;
    cout << "Value at 2nd entry of VTable " << (int*)*((int*)*(int*)(&obj+0)+1) << endl;

    return 0;
}

OUTPUT:

VPTR's Address 0012FF7C
VIRTUAL TABLE 's Address 0046C0EC
Value at first entry of VIRTUAL TABLE 0040100A
Value at 2nd entry of VIRTUAL TABLE 004012


Example :9

Code: cpp

class Test
{
    virtual void fun1() { cout << "Test::fun1" << endl; }
    virtual void func1() { cout << "Test::func1" << endl; }
};

typedef void(*Fun)(void);

int main()
{
    Test obj;
    Fun pFun = NULL;

    // calling 1st virtual function
    pFun = (Fun)*((int*)*(int*)(&obj+0)+0);
    pFun();

    // calling 2nd virtual function
    pFun = (Fun)*((int*)*(int*)(&obj+0)+1);
    pFun();

    return 0;
}

OUTPUT:

Test::fun1
Test::func1

Example 10: multiple Inheritance

Code: cpp

class Base1
{
public:
    virtual void fun();
};

class Base2
{
public:
    virtual void fun();
};

class Base3
{
public:
    virtual void fun();
};

class Derive : public Base1, public Base2, public Base3
{
};

int main()
{
    Derive obj;
    cout << "Derive's Size = " << sizeof(obj) << endl;
    return 0;
}

OUTPUT:

Derive's Size = 12


Example 11: Calling Virtual Functions in case of Multiple Inheritance
Code: cpp

class Base1
{
    virtual void fun1() { cout << "Base1::fun1()" << endl; }
    virtual void func1() { cout << "Base1::func1()" << endl; }
};

class Base2 {
    virtual void fun1() { cout << "Base2::fun1()" << endl; }
    virtual void func1() { cout << "Base2::func1()" << endl; }
};

class Base3 {
    virtual void fun1() { cout << "Base3::fun1()" << endl; }
    virtual void func1() { cout << "Base3::func1()" << endl; }
};

class Derive : public Base1, public Base2, public Base3
{
public:
    virtual void Fn()
    {
        cout << "Derive::Fn" << endl;
    }
    virtual void Fnc()
    {
        cout << "Derive::Fnc" << endl;
    }
};

typedef void(*Fun)(void);

int main()
{
    Derive obj;
    Fun pFun = NULL;

    // calling 1st virtual function of Base1
    pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+0);
    pFun();

    // calling 2nd virtual function of Base1
    pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+1);
    pFun();

    // calling 1st virtual function of Base2
    pFun = (Fun)*((int*)*(int*)((int*)&obj+1)+0);
    pFun();

    // calling 2nd virtual function of Base2
    pFun = (Fun)*((int*)*(int*)((int*)&obj+1)+1);
    pFun();

    // calling 1st virtual function of Base3
    pFun = (Fun)*((int*)*(int*)((int*)&obj+2)+0);
    pFun();

    // calling 2nd virtual function of Base3
    pFun = (Fun)*((int*)*(int*)((int*)&obj+2)+1);
    pFun();

    // calling 1st virtual function of Drive
    pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+2);
    pFun();

    // calling 2nd virtual function of Drive
    pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+3);
    pFun();

    return 0;
}

OUTPUT:

Base1::fun
Base1::func
Base2::fun
Base2::func
Base3::fun
Base3::func
Drive::Fn
Drive::Fnc


Asadullah Ansari
( Trueth can'nt be Changed)

Recommended Answers

All 6 Replies

In Example 11, i expected the virtual ptr for derived class to be at

(int *)*((int *)(&obj)+3)

Hpwever, the VPTR is at

(int *)*((int *)(&obj)+0)

Can some body explain this please?

Thanks in advance !

I think, it's an absolutely aimless article (and discussion too), because of VTBL is not a part of C++ language. If you want to know how virtual functions calls were implemented in the specific C++ implementation. search Google (or what else;)), for example:

http://forums.msdn.microsoft.com/ru-RU/vclanguage/thread/0e2d1b36-1805-46de-afe8-ce7b6348fe28
http://bytes.com/forum/thread535605.html

I have no time to copy/paste all URLs;)...

See also
http://www.gidforums.com/t-17557.html

Storm in a teacap...

@kneiel: The Virtual pointer for Derive class is at
(int *)*((int *)(&obj)+0)

instead of
(int *)*((int *)(&obj)+3)

Because the virtual pointer for derive class does not get cretaed separeatly for derived class.In Example11 we have 3 virtual table because we have multiple inheritance where there are 3 base classes.And each of the V Table will have entries for the virtual functions of the derive class.

Thats why we dont have a vTable for derive class ..So no VPTR for derive class V Table.

Really a nice explanation on VPTR n VTABLE concepts. thanks a lot as its so much beneficial in understanding these concepts.

There will be four VTables i guess,three for the base classes and one for the derived class which will have the entries for all the virtual function addresses of the base classes it is derived from and its own virtual function addresses.

Thanks. You helped me a lot.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.