Instead of using virtual functions where there is a lookup to the vtable pointer in the object, which then takes you to the vtable, containing a pointer to the function- would it not be possible to just contain a data member in the object which points directly to the function?
-
1If the compiler know the static type of the object it can optimize the call to be a direct call. I think this optimization is common, but I'm not 100% sure. If the compiler can't do this then having your own pointer in the object (and whatever code you'd need to take advantage of it) would likely be a lot less optimized than the compiler just using the pointer in the vtable. – Michael Burr Nov 24 '14 at 20:33
-
1What would be the size of your objects if you add all the pointers in each ? – quantdev Nov 24 '14 at 20:34
-
2which means, that you have for each virtual member a data member in each instance. This is a bit faster but much larger in size. You save only one indirection for the call but get a huge amount of wasted data space. – Klaus Nov 24 '14 at 20:34
-
Ok say my objects only have one virtual interface method. This solution would be better? In fact you dont even have to store a 8 byte pointer, you could just store an offset from a data member. – user997112 Nov 24 '14 at 20:51
-
@user997112: no, it would have to be a pointer to the function which is stored in the program code, functions are not in the object's space. It would require a full 8 byte pointer. Odds are, if you have a virtual function, you also need a virtual destructor, so you're going to need at least those two 8 byte pointers. – Mooing Duck Nov 24 '14 at 21:40
-
1Related: http://stackoverflow.com/questions/5417829/how-can-c-virtual-functions-be-implemented-except-vtable?rq=1 – Mooing Duck Nov 24 '14 at 21:42
1 Answers
If I understand your question, you are looking for a way to implement polymorphism using a function pointer.
Well, it is possible but extremely cumbersome, error prone, but it'll be difficult to outperform de generated by your compiler for virtual function calls.
How to do it ?
The idea is to use a function pointer. In order to implement polymorphims, it must be in the base class.
class B { // Base class
protected:
void (B::*fptest)(); // Function pointer to member function
public:
void mtest() // Class specific mebmer function
{ cout << "Base test\n"; }
void itest() // Polymorphic function
{ (this->*fptest)(); } // implemented by calling the poitner to member function
B() : fptest(&B::mtest) { } // Ctor must initialize the function pointer
virtual ~B() {}
};
class D : public B { // Derived class
public:
void mtest() // Class specific mebmer function
{ cout << "Derived test\n"; }
D() // Ctor
{ fptest = reinterpret_cast<void(B::*)()>(&D::mtest); } // not sure it's this safe in case of multiple inheritance !!
};
Code to test this construct:
B b;
D d;
B *pb = &b, *pd = &d;
pb->itest();
pd->itest();
Is it safe ?
There are severe limitations to this. For example:
- You have to ensure that every derived class initializes correctly the function pointer.
- In case of multiple inheritance, the function pointer cast to the base class member might not work as expected.
- There is no overloading of pointers possible. So you'll need a different pointer for every possible signature. That could be pretty odd.
Is it more performant than vtable lookup ?
No: look at the assembler executed for every polymorphic call to itest()
:
; 41 : pd->itest(); // cod for the call for a derived object
mov ecx, DWORD PTR _pd$[ebp] ; load the oject address
call ?itest@B@@QAEXXZ ; call B::itest
; 16 : void itest() { (this->*fptest)(); }
push ebp
mov ebp, esp
sub esp, 68 ; 00000044H
push ebx
push esi
push edi
mov DWORD PTR _this$[ebp], ecx ; use address of object as parameter
mov eax, DWORD PTR _this$[ebp] ; load the function pointer
mov ecx, DWORD PTR _this$[ebp] ; " "
mov edx, DWORD PTR [eax+4] ; call the function pointer
call edx
pop edi
pop esi
pop ebx
mov esp, ebp
pop ebp
ret 0
Of course, the optimizer could inline the code, removing some push and pop but the general principle is that the code for the indirection will be generated.
Isn't vtable lookup performant enough ?
Well a vtable lookup is basically loading a function pointer from a fixed offset calculated by the compiler. The assembler code for callling a vitual test() function would look like this:
39 : pd->test();
mov eax, DWORD PTR _pd$[ebp]
mov edx, DWORD PTR [eax]
mov ecx, DWORD PTR _pd$[ebp]
mov eax, DWORD PTR [edx]
call eax
Conclusion
A vtable lookup is at least as performant that a call through a function pointer. The compiler takes care of all the initialisation and the most complex inheritance situations. Better use the powerfull of virtual functions instead of trying to manually outperform your compiler.

- 68,716
- 7
- 72
- 138
-
Without turning on optimization this test doesn't really demonstrate anything useful. – Mark Ransom Nov 24 '14 at 23:17
-
@MarkRansom the best would probably be to do a benchmark for the specific case of the OP, because you can't either generalize from the optimizations performed on oversimplified demo code. – Christophe Nov 24 '14 at 23:53