0
votes

In the given example 3 VTables are created and 3 vptr are created.

But I guess there will be four VTables, 3 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. Size of object obj is 12. It means it has 3 vptr. But vptr is created per object. Here one object is created, how do we have 3 vptrs.

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;
    std::cout << "size:" << sizeof(obj) << std::endl;
    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;
}

In this Example, I expected the virtual ptr for derived class to be at

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

However, the VPTR is at

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

Can some body explain this please? Thanks in advance !

2
Why did you expect what you were expecting? What gave you the right to hold any kind of expectations? (Please cite references.) - Kerrek SB
"one object is created, how do we have 3 vptrs"? The object inherits from 3 classes. - barak manos

2 Answers

0
votes

The table for a derived class can be implemented as an extension of the table for a base class, adding any new virtual functions to the end. The resulting table can be used for either class - for the base class, any extra functions at the end are simply ignored.

This means that the Derive object can share tables with one of the three base sub-objects, so only three tables are needed in total.

0
votes

In multiple inheritance, there are multiple vptr's stored in the object i.e one per base class. Also, special vtbls must be generated for base classes in addition to the stand-alone vtbls.

One more important thing:-

You should never assume that position of vptr is at object's beginning. It could even be at the end OR say in the middle. It's completely dependant on compiler vendors how they choose to implement it.