gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

Beginners > function pointers

#8848 - hnager - Mon Jul 21, 2003 6:30 pm

Hmmm, having a bit of trouble getting function pointers working - I have one member function pointer called update which I want to point at a variety of other member functions (to replace a case/switch) which I currently evaluate everyframe - if you're moving do this, otherwise do that, etc.

But everytime I try to compile i get an error - can't convert void (*) to void(*Sprite::) or something along those lines...(I don't have devkit set up at work)

Are function pointers possible with g++?

#8849 - sgeos - Mon Jul 21, 2003 6:36 pm

hnager wrote:
void (*) ... void(*Sprite::) ... g++?


I don't do the C++ thing, but in C I've always declared function pointers like this:

void *(*fptr)(void) = map_init; // map_init() is a function
void (*fptr2)(int, int, const char *) = text_e; // text_e() is a function
int (*rng)(int, int) = dice; // dice() is a function

-Brendan

#8852 - hnager - Mon Jul 21, 2003 7:24 pm

I'm basically doing that same thing (from what I can remember):

class Sprite {
Sprite();
~ Sprite(){}
void move(){};
void (*Sprite::update)();
...
}

Sprite::Sprite(){
update = &Sprite::move; //this has less complaints than update = move
}

What needs to change to work within a class?

#8855 - sgeos - Mon Jul 21, 2003 11:24 pm

Again, I don't do the C++ thing, so I'm not sure how classes work. I've been trained to always be explicit and resort to defaults, so if this is what you mean, then it is what I'd type in:

Code:
    void (*Sprite::update)(void);


Function pointers are very particular about return types and the parameters passed to them.

Code:
int a(void)
{
}

int b(void)
{
}

void c(int)
{
}

int (*fptr)(void);  // will work with a() or b() but not c()


-Brendan

#8856 - col - Tue Jul 22, 2003 12:01 am

hnager wrote:
I'm basically doing that same thing (from what I can remember):

class Sprite {
Sprite();
~ Sprite(){}
void move(){};
void (*Sprite::update)();
...
}

you have the '*' in the wrong place - try this:
Code:

class Sprite {
    Sprite();
   ~ Sprite(){}
    void move(){};
    void (Sprite::*update)();
    ...
}

Quote:

Sprite::Sprite(){
update = &Sprite::move; //this has less complaints than update = move
}

your assumption is correct, you _must_ use the address of operator '&' explicitly when assigning a member function to a pointer

then to use its somthing like

Code:

Sprite sprite1;
Sprite* sprite2 = new Sprite();
...
...
(sprite1.*update)();
(sprite2->*update)();
...
...



hope this helps
cheers

Col

#8859 - hnager - Tue Jul 22, 2003 1:32 am

Thanks ! That did the trick - well, until I tried to derive from Sprite:

class Sprite {
Sprite();
~ Sprite(){}
void move(){};
void (Sprite::*update)();
...
};

class Ant : public Sprite {
Ant();
~Ant(){}
void crawl(){};
};

Ant::Ant(){
update= &Ant::crawl;
}

no surprise:

cannot convert `void (Ant::*)()' to `void (Sprite::*)()' in
assignment

Any ideas - workarounds? basically I want to have all of my sprites derive from the base class so that they come predefined with the function pointer so that I can have a vector of 'Sprites' and tell each to update() each frame...the different classes and instances would take care of knowing what update should do.

#8863 - Quirky - Tue Jul 22, 2003 7:34 am

I think you're trying to use a C "trick" (function pointers) to do something that you should really be using a C++ approach to accomplish.

You should have your Ant class override move() so that calling mySprite.move() where mySprite is an instance of Ant, though you only know it to be "some Sprite-type class" will at run time call the Ant class's move(). Internally, Ant's move would call crawl (which could be a private function, for example)

#8865 - hnager - Tue Jul 22, 2003 12:14 pm

Makes sense - as a work around i defined update as a virtual method of Sprite:

virtual void update(){}

and then within Ant (derived from Sprite) I have a function pointer decalared then assigned in the constructor. The overriden method update() in Ant just calls that function pointer. I have an 'event engine' in place which loops through all of the Sprites registered to it and tells them to update() every frame.

That works, but I was hoping to take care of the function pointer declaration within Sprite and then just assign it in derived classes, for example, I have variables x and y inheritted from Sprite which can be set just as if declaed as part of Ant.

Is the problem with the function pointer that I have to explicitly declare it as part of Sprite? (Sprite::*update)();

#8867 - Sweex - Tue Jul 22, 2003 3:05 pm

No no nooh!;-)

As far as I understand the problem, you should not call the function pointer from your virtual function Update. The actual implementation of the function pointer it is calling should be in there. No messing about with function pointers at anymore!

#8872 - hnager - Tue Jul 22, 2003 3:45 pm

??

Not sure if I understand what you mean - what is the issue with calling a function pointer from the virtual function update? I'm overriding update() in derived classes - it itself is not the function pointer (that's called funcptr for now), it just calls the function pointer.

My approach previously was to use a case/switch to figure out what to do in the update() function - but instead I was hoping to just reassign funcptr and call that,

#8873 - Sweex - Tue Jul 22, 2003 4:05 pm

...Example... (This is pretty basic C++ btw.)

Code:

class Sprite
{
  Sprite();
  ~Sprite(){}

  virtual void move() {};
  void update() { move(); }
};

class Ant : public Sprite
{
  Ant();
  ~Ant(){}

  void move(){ /* "Crawl" code should go here*/ };
};

// Another class to indicate it's generic use
class AntQueen : public Ant
{
  AntQueen();
  ~AntQueen(){}

  virtual void move(){ /* Ant queen specific code */ };
};


// your main function
void main()
{
  Ant ant();
  AntQueen queen();

  // Move your insects, each by calling update
  ant.Update();
  queen.Update();

  // And even better
  Sprite* insects[2];
  insect[0] = &
  insect[1] = &

  // Update all your insects in a loop
  for (int i=0;i<2;i++)
  {
    insect[i].Update(); // The program will work out which Update function to call
  }
}


Good luck!:)

#8880 - hnager - Tue Jul 22, 2003 6:26 pm

Thanks for the example - that's what I had prior - the problem I have is that update() for one instance of a sprite may be different than another - in one case an ant may be moving, in another it may be 'resting' - that's where my case/switch used to come in to play...what i want to do is just reassign the function pointer so when i tell an ant to 'rest' it assigns the function pointer to be 'rest()' - it all works except that I can't declare the function pointer in the base class, so I have to assign it in every derived class.

#8881 - Sweex - Tue Jul 22, 2003 7:10 pm

Ah, I get it now... Can obviously be done in ++ as well, but then you can argue whether it's worth the trouble.

Can't help you much further with the function pointers then. Personally I'd either program a switch statement or use a statemachine (Read some articles about them if you're unfamiliar with them; they're very useful for this problem!)

#8882 - hnager - Tue Jul 22, 2003 8:14 pm

I'm trying to get away from the switch statement - I'll do some looking around for state machines - thanks!