This code is to explain how polymorphism works through virtual functions and how C++ does it using VPTR and VTABLE. Please refer to my last post - C++ test code on virtual functions – to understand this better.
Code example to find out VPTR and VTABLE in C++ class. And use it to show how polymorphism works in C++. That is same base class pointer can be used to invoke functions of the derived class. C++ achieves this by changing the VPTR pointer to new drived classes VTABLE. VPTR and VTABLE usage for polymorphism in C++ Class expalined diagrammatically below. The base class object VPTR changes when base class is instantiated with that sub class, to point to the VTABLE of that sub class. '?' - denotes VPTR will decide what subclass is currently instantiated to the base class. BaseClass Object (pobj) SubClass_1 | VTABLE (vtable) v | +------------+ v | VPTR (vptr)| *-->+------------+ +------------+ ? | VTEntry1 |------------> +------------+ | DATA1 (a) | * +------------+ | func1() | +------------+ | | VTEntry2 |--------+ | | | DATA2 (b) | | +------------+ | | | +------------+ | | . | | +------------+ | . | | | . | | | . | | | . | +---->+------------+ | . | | | func2() | | . | | | | | | | | +------------+ | SubClass_2 | VTABLE (vtable) | | | v +-->+------------+ | VTEntry1 |------------> +------------+ +------------+ | func1() | | VTEntry2 |--------+ | | +------------+ | | | | . | | +------------+ | . | | | . | +---->+------------+ | func2() | | | | | +------------+ |
And this is how the class hierarchy looks like in the following code.
+------------------+ | BaseClass | +------------------+ / \ / \ / \ V V +------------------+ +------------------+ | SubClass_1 | | SubClass_2 | +------------------+ +------------------+ |
typedef void (*func)(void); // class member function type typedef int* ptr; // 32 bit system pointer type class BaseClass { private: int a; // DATA1 public: BaseClass() : a(0) {} // pure virtual function virtual void func1() =0; virtual void func2() =0; static void deref_vtable(ptr); }; class SubClass_1 : public BaseClass { public: void func1() { cout << "SubClass_1::func1" << endl; } void func2() { cout << "SubClass_1::func2" << endl; } }; class SubClass_2 : public BaseClass { public: void func1() { cout << "SubClass_2::func1" << endl; } void func2() { cout << "SubClass_2::func2" << endl; } }; // static function to dereference the vtable entries void BaseClass::deref_vtable(ptr vtable) { func pfunc = NULL; // dereferencing first (VTABLE1) entry in VTABLE pfunc = (func)*(vtable+0); pfunc(); // dereferencing second (VTABLE2) entry in VTABLE pfunc = (func)*(vtable+1); pfunc(); return; } int main(int argc, char * const argv[]) { BaseClass *pobj = NULL; ptr vptr, vtable; // first sub class pobj = new SubClass_1; vptr = (ptr)pobj; // first address of obj (class) points to vptr vtable = (ptr)*vptr; // dereferencing vptr to get vtable cout << "vptr: " << vptr << " " << "vtable: " << vtable << endl; BaseClass::deref_vtable(vtable); delete pobj; cout << endl; // second sub class pobj = new SubClass_2; vptr = (ptr)pobj; // first address of obj (class) points to vptr vtable = (ptr)*vptr; // dereferencing vptr to get vtable cout << "vptr: " << vptr << " " << "vtable: " << vtable << endl; BaseClass::deref_vtable(vtable); delete pobj; return 0; } |
Output:
vptr: 0x9934008 vtable: 0x8048cf8 SubClass_1::func1 SubClass_1::func2 vptr: 0x9934008 vtable: 0x8048ce8 SubClass_2::func1 SubClass_2::func2 |
No comments:
Post a Comment