choosing vptr in case of multiple inheritance

Viewed 707

This is similar to many previous questions, but it asks something which I was not able to find answer.

#include <iostream>
using namespace std;

class Base1 {
    public:
        int b1_data;
        virtual void b1_fn() {cout << "I am b1\n";}
};
class Base2 {
    public:
        int b2_data;
        virtual void b2_fn() {cout << "I am b2\n";}
};
class Derived : public Base1, public Base2 {
    public:
        int d_data;
        void b1_fn() {cout << "I am b1 of d\n";}
        void b2_fn() {cout << "I am b2 of d\n";}
};

int main() {
    Derived *d = new Derived();
    Base1 *b1 = d;
    /*My observation mentioned below is implementation dependant, for learning,
    I assume, there is vtable for each class containing virtual function and in
    case of multiple inheritance, there are multiple vtables based on number of
    base classes(hence that many vptr in derived object mem layout)*/

    b1->b1_fn(); // invokes b1_fn of Derived because d points to 
                 // start of d's memory layout and hence finds vtpr to
                 // Derived vtable for Base1(this is understood)
    Base2 *b2 = d;
    b2->b2_fn(); // invokes b2_fn of Derived but how? I know that it "somehow" 
                 // gets the offset added to d to point to corresponding Base2 
                 // type layout(which has vptr pointing to Derived vtable for 
                 // Base2) present in d's memory layout. 
    return 0;
}

Specifically, how does b2 point to vptr for vtable of Derived for Base2 to get to b2_fn()? I've tried seeing memlayout dump from gcc but couldn't figure out much.

2 Answers
#include <iostream>

using namespace std;


class Base1 {
public:
    virtual void b1_fn() {cout << "I am b1\n";}
};
class Base2 {
public:
    virtual void b2_fn() {cout << "I am b2\n";}
};
class Derived : public Base1, public Base2 {
public:
    void b1_fn() {cout << "I am b1 of d\n";}
    void b2_fn() {cout << "I am b2 of d\n";}
};

int main() {


Base1 b1;
Base2 b2;
Derived d;

cout<<"size of base1 object"<<sizeof(b1)<<endl;
cout<<"size of base2 object"<<sizeof(b2)<<endl;
cout<<"size of derived object"<<sizeof(d)<<endl;
return 0;

}

Output of above program is: 8 8 16

So you can see that derived object has inherited two vptr from base1 and base2

both vptr in derived class points to vtable of derived class. since you have overriden the base methods in derived class so vptr will point to the derived class methods.

In case you had not overriden methods in derived class than vtable would be having address of base class methods and vptr would be pointing to those

Thats why b2->b2_fn(); calls derived method

Related