Summary
A rather unpleasant name, but a very useful pattern.
Advertisement
I have been using a technique of creating static function pointer tables in order to achieve efficient signature-based polymorphism over and
over again. I think it is time I elevated it to Pattern status. Here is how the Static Function Pointer Table Polymorphism Pattern works:
Let's say I want to emulate the behaviour of a duck-typed interface FuBar which looks like the following psuedo-code:
interface FuBar {
int Fu();
int Bar(int x);
}
First I declare an appropriate function pointer table type:
struct FuBarTable {
int(*Fu)(void* pseudo_this);
int(*Bar)(void* pseudo_this, int x);
};
Then I declare a static adapter.
template<typename T>
struct StaticFuBarAdapter {
static int Fu(void* pseudo_this) { return reinterpret_cast<T*>(pseudo_this)->Fu(); }
static int Bar(void* pseudo_this, int x) { return reinterpret_cast<T*>(pseudo_this)->Bar(x); }
};
Now I create a function which returns the address to a static FuBarTable for a given type T.
I don't know what I would call it, but there is something rather beautiful about this... it goes around the usual way OO is done, and yet it does not offend me. I wonder if this can be scaled to large applications and not create a headache.
What would be the advantage of this over inheritance-based polymorphism (MyFuBar and YourFuBar inherits from FuBar)? FuBar does some computations in its constructor, so it might well be slower than using virtual functions (essentially, it looks like an emulation of virtual functions).
You have a chance the compiler can make this very efficient. GetFuBarTable() is all static computations, so it should be easily inlined by a compiler.
> (essentially, it looks like an emulation of virtual > functions).
Yep. That is very much what it is, except for one small difference. The class internally does no dynamic dispatching.
> What would be the advantage of this over inheritance-based > polymorphism (MyFuBar and YourFuBar inherits from FuBar)?
It is definitely not flat-out better, but it can be useful in some circumstances.
- You can plug into classes which are for some reason not modifiable, just like the External Polymorphism pattern. - The class does not have to store a virtual table function pointer internally - You can avoid the tight coupling which results from inheritance - A class does not have to declare in advance it is implementing an interface, it does so incidentally. This results in duck-typing, or signature based polymorphism. - Intra-method calls are inlinable. When one member function calls a virtual function, it can't inline it.