Pergunta

I was going through the code which I got from somewhere to understand how vptr and vtable works. Following is the code with the output

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 Derive
pFun = (Fun)*((int*)*(int*)((int*)&obj+0)+2);
pFun();

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

OUTPUT:
Base1::fun
Base1::func
Base2::fun
Base2::func
Base3::fun
Base3::func
Derive::Fn
Derive::Fnc

It looks OK but the way the virtual functions of derived class are called is not understood. Shouldn't it be this way:

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

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

which meant to be the address of virtual functions accessed using vptr of the derived class which ultimately is pointing to the vtable of the derived class.

Foi útil?

Solução

The whole idea of object oriented programming is to follow abstraction. When you have virtual function, meant for dynamic binding, use it through the abstraction by calling the virtual function for the base class pointer. Depending on where it is pointing dynamically in the class hierarchy, it will dynamically bind. Why should you go deeper to break the abstraction and use the vtbl etc (where implementation varies from compiler to compiler based on some guideline). So suggestion is to use dynamic binding in good spirit.

Outras dicas

It looks like the new virtual functions in Derive are added to the end of the first base class's vtable, rather than put in a separate table. That makes sense: it's more efficient to extend an existing table than to add an extra one, which would bloat each object with an extra pointer for each level of inheritance.

All of this is implementation-dependent of course. The language doesn't specify how virtual dispatch should be implemented, only how it should work when used normally.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top