What's the point of Function Pointers?

Started by
14 comments, last by abstractworlds 19 years, 4 months ago
In C++, what's the point of a function pointer? So a function pointer will allow me to point to different sections of code without a switch statement. For example, if I have different game states (Menu, In Game, End Game, for example), I can have a switch statement:

switch(g_CurrentGameState)
{
case GAMESTATE_MENU:
RunMenu();
break;
case GAMESTATE_INGAME:
RunGame();
break;
case GAMESTATE_ENDGAME:
RunEnd();
break;
default:
throw();
}
But instead of that I can do that with function pointers:

//Globals
void (*pGameState)();
pGameState g_GameState[3];
//Set up in main
g_GameState[GAMESTATE_MENU] = RunMenu;
g_GameState[GAMESTATE_INGAME] = RunGame;
g_GameState[GAMESTATE_ENDGAME] = RunEnd;
//In place of the switch above
g_GameStatePointers[g_CurrentGameState]();

Okay, I can see that. There are some huge limitations in this though: There's no type safety (what if I did a RunOther(int, char) and did g_GameState[0] = RunOther;?), and I can't use member data (because I can't point to non-static member functions). Why not instead use a class with a virtual function? For example:

//global
class GameState
{
public:
    virtual void Run()=0;
};
//main
GameCore TheCore(Bunch, of, Core, Options, Here);//Note this is in a function, not a global declaration.
GameState* AvailableGameStates[3];
GameState_Menu GS_Menu;
GameState_GameCore GS_Game(&TheCore);
GameState_EndGame GS_End;
AvailableGameStates[GAMESTATE_MENU] = &GS_Menu;
AvailableGameStates[GAMESTATE_INGAME] = &GS_Game;
AvailableGameStates[GAMESTATE_ENDGAME] = &GS_End;
//in place of switch
AvailableGameStates[g_CurrentGameState]->Run();


In this case I can now use any data I want. For example, say I have a GameCore object that I wanted to call the member function DoFrame() on with the function pointers. Well this works (while function pointers don't):

class GameState_GameCore : public GameState
{
protected:
    GameCore* TheCore;
    GameState_GameCore(const GameState_GameCore& rs){}
    GameState_GameCore& operator=(const GameState_GameCore& rs){ return *this; }
public:
    GameState_GameCore(GameCore* ToRun) : TheCore(ToRun){}
    virtual void Run() { TheCore->DoFrame(); }
};
In this case I've accessed a non-static member function. Note that combining the two sources you can see I'm also accessing an object that has no referance in the global namespace. I can't think of a way to do this using global functions. Now I'm a firm believer in "every tool has a job", and so I'm wondering... what's the job of a function pointer? The virtual-function-in-a-class seems to be better at doing (what I've been told is) the Function Pointer's job. The only place I can think to use function pointers is in dynamically linked DLLs (that is, LoadLibrary("DLLName"); rather than linking the lib) since I can't use classes across them. Also perhaps for a bit more speed than classes. Can anyone tell me what's the use of function pointers?
----Erzengel des Lichtes光の大天使Archangel of LightEverything has a use. You must know that use, and when to properly use the effects.♀≈♂?
Advertisement
Look up how qsort works. That's a pretty good example of good function pointer usage. Also there's a bunch of stuff in the windows api that uses function pointers for callbacks. Sure, they could've done it with inheritance and base classes and stuff, but 1) it would be overkill in most cases and 2) it wouldnt work in C.
You can do function pointers to class members, the syntax is a bit weird though:

typedef void (CClassName::* FUNCTION_TYPE)( int, int, unsigned long );

I've used function pointers for a DC-like class to work on pixel data. Once the bitdepth is changed it will reassign the copy/draw function pointers to the appropriate functions for that particular depth or fallback to slower, but general functions.

I couldn't have done it with a base class and inherited classes for every pixel format available because i can change the format on the fly (can't change my own type, can i?).

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

Here's an example of how I use function pointers. My game engine is a 2D engine, and almost every game object is either a Sprite or derived from a Sprite. However, there are times when I simply don't want to worry about creating a whole new class for some simple behavior. Maybe I want to have a bunch of balls bounce off the ground, or maybe clouds that move and grow and shrink to give them a little bit of activity. These are basic behaviors, so what I do in those cases is use a function pointer (it's in C#, so it's actually events, but similar concept).

I just simply create my functions for each type of behavior, and assign the Sprite's function pointer. Then my engine knows to look at every Sprite, see if it has a behavior assigned, and if so, it calls it.

So, function pointers are ways that the same function can give you different behaviors. They're not really necessary, and you could get around using them if you really wanted to, but sometimes they just make things easier.

--Vic--
You really should try to see if your understanding of a particular concept is correct before you start complaining about how it's not useful or implemented in a useful manner.
In this case, for instance, none of your complaints about the shortcomings of function pointers are correct, and even a little searching should reveal that.
First of, there *is* type safety, as
void(*)()
and
void(*)(int)
are two different types that cannot be assigned to each other.
In other words, this will fail:
void foo();void bar(int);void(*pfn)(); // pfn is a pointer to a void function with no argsint main() {  pfn = foo;  // ok, types match  pfn = bar;  // will fail, type mismatch}


Your other specific complaint was that it won't allow you to point to member functions, which is also incorrect:
class Test {public:  void Foo();};void(Test::*pfn)();  // pfn is of type pointer to Test member funcint main() {  pfn = &Test::Foo;   // Assign to Test::Foo  Test t;  (t.*pfn)();  // Call test.foo()}


As for virtual member functions vs. function pointers they serve completely different needs.

But, after all, you asked for the point of a function pointer.
Consider a generic sorting sorting function (such as std::sort), that can operate on any given type of data. How will the function know how to compare the elements its given? It could simply suppose that operator< is suitably defined, of course, but that would severely limit the usefulness of sort. Consider this, for instance:
struct CD {  string title;  string artist;  int year_published;  /* other stuff */};bool compareTitle ( CD const& cd1, CD const& cd2 ) {  return cd1.title < cd2.title;}bool compareArtist ( CD const& cd1, CD const& cd2 ) {  return cd1.artist < cd2.artist;}bool compareYearPublished ( CD const& cd1, CD const& cd2 ) {  return cd1.year_published < cd2.year_published;}vector<CD> cdCollection;int main() {  /* Assuming cdCollection is filled with CD's */    // Sort by title  sort ( cdCollection.begin(), cdCollection.end(), compareTitle );   // Sort by artist  sort ( cdCollection.begin(), cdCollection.end(), compareArtist );  // Sort by year  sort ( cdCollection.begin(), cdCollection.end(), compareYearPublished );}

In cases like this function pointers (or functors) are invaluable, and the same results cannot be achieved elegantly in another fashion.

Hope that clears things up a little.

- Neophyte

EDIT: Tag typos
EDIT: Another typo
What's the point of loop statements if we can just use an if statement and a goto?

Programming is little more than expressing your intentions in a manner that can be comprehended by both human and machine alike.
--God has paid us the intolerable compliment of loving us, in the deepest, most tragic, most inexorable sense.- C.S. Lewis
lol with a System.Data.DataSet and a table with Key/Value lookups to various functions, you could have the completely generic object!

We are storing guids that are linked to code with the GuidAttribute, and essentially using our own function pointers for VB.NET/C#.

It really is working quite nicely, as we can allow the user to edit what behaviors an object has at runtime.

Quote:Original post by Neophyte
You really should try to see if your understanding of a particular concept is correct before you start complaining about how it's not useful or implemented in a useful manner.

That is the point of my post: to get a better understanding of the particular concept. I wasn't complaining about them, I asked what their use is. I did a lot of searches about function pointers and everything I found about function pointers says that you can't use it to point at non-static member functions, which seemed like a gigantic limitation to its usefulness.

Thank you all for your replies.
----Erzengel des Lichtes光の大天使Archangel of LightEverything has a use. You must know that use, and when to properly use the effects.♀≈♂?
Look into functors. They let you treat class member pointers the same way as you would normal/static class member function pointers.
--God has paid us the intolerable compliment of loving us, in the deepest, most tragic, most inexorable sense.- C.S. Lewis
Quote:Original post by antareus
Look into functors. They let you treat class member pointers the same way as you would normal/static class member function pointers.

They're also type safe, capable of holding state, compatible with function pointers (with some amount of work) and have lots of other advantages. Take a look at boost libraries for built in support.

This topic is closed to new replies.

Advertisement