Weblogs Forum
The Static Function Pointer Table Polymorphism Pattern

3 replies on 1 page. Most recent reply: Aug 17, 2005 5:41 AM by Christopher Diggins

 Previous Topic Next Topic
 Flat View: This topic has 3 replies on 1 page
 Christopher Diggins Posts: 1215 Nickname: cdiggins Registered: Feb, 2004
The Static Function Pointer Table Polymorphism Pattern (View in Weblogs)
Posted: Aug 16, 2005 10:45 AM
Summary
A rather unpleasant name, but a very useful pattern.
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>
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.
```  template<typename T>
FuBarTable* GetFuBarTable() {
static FuBarTable table = { U::Fu, U::Bar };
return &table;
};
```
Finally I bundle a pointer to the table, and a pointer to the object in a single polymorphic reference type.
```  struct FuBar {
template<typename T>
FuBar(T& x) {
object = &x;
table = GetFuBarTable<T>();
}
int Fu() {
return table->Fu(object);
}
int Bar(int x) {
return table->Bar(object, x);
}
private:
void* object;
FuBarTable* table;
}
```
Now I can write:
```  struct MyFuBar {
int Fu() { return 1; }
int Bar(int x) { return Fu() + x; }
};

struct YourFuBar {
int Fu() { return 2; }
int Bar(int x) { return Fu() + x; }
};

void DoFuAndBar(FuBar fb) {
cout << fb.Bar(fb.Fu()) << endl;
}

int main() {
MyFuBar fb1;
DoFuAndBar(fb1);
YourFuBar fb2;
DoFuAndBar(fb2);
}
```
Voila! Polymorphism the hard way. If you can think of a better name, I am very open to suggestions.

 Michel Parisien Posts: 25 Nickname: kriggs Registered: Jul, 2005
Re: The Static Function Pointer Table Polymorphism Pattern Posted: Aug 17, 2005 4:49 AM
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.

 Terje Slettebø Posts: 205 Nickname: tslettebo Registered: Jun, 2004
Re: The Static Function Pointer Table Polymorphism Pattern Posted: Aug 17, 2005 5:17 AM
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).

 Christopher Diggins Posts: 1215 Nickname: cdiggins Registered: Feb, 2004
Re: The Static Function Pointer Table Polymorphism Pattern Posted: Aug 17, 2005 5:41 AM
> FuBar does some computations in its constructor, so it
> might well be slower than using virtual functions

If you rewrite the constructor as:

`  FuBar(T& x) : object(&x), table(GetFuBarTable<T>()) { }`

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.

I hope this helps?

 Flat View: This topic has 3 replies on 1 page
 Previous Topic Next Topic