Skip to main content
GameDev.net gamedev.net
🔒 Locked

Function pointers pointing to class functions?

Started by Roof Top Pew Wee Nov 9, 2001 at 4:50 PM 29 replies 800+ views
Original Post
Roof Top Pew Wee
Roof Top Pew Wee
Here''s a simplified version of what I am trying to do: typedef void (*voidFunction) (); class A {public: void functionA(){} }; class B {public: voidFunction functionPointer; void setFunction(voidFunction functionToSetTo) { functionPointer = functionToSetTo; } }; int main() { A classA; B classB; classB.setFunction(&(classA.functionA)); } The error I get is: ''&'' : illegal operation on bound member function expression. Pretty much, I have a function pointer in class A and I want it to point to the function in class B. I have gotten classes (A in this case) to be able to point to functions not contained in a class, but how do I get it to point to a function inside of a class (B in this case). Thanks for any help. --Vic--
Roof Top Pew Wee
Roof Top Pew Wee
Funny, every piece of function pointer code I''ve written has needed it. I did try it without the & and here''s the error:

C2664: ''setFunction'' : cannot convert parameter 1 from ''void (void)'' to ''void (__cdecl *)(void)''

I''m pretty sure that when you pass the function, you either have to give it the address or cast it with they type I''ve defined.

--Vic--
Dire.Wolf
Dire.Wolf
Change

classB.setFunction(&(classA.functionA));


to

classB.setFunction(&classA::functionA);

Also there is another problem, your typedef is not a member function pointer.

It needs to be:

typedef void (classA::*voidFunction) ();

I'm in the middle of something right now so there may be more issues...I'll check over it again in a sec.

BTW You must use the & operator to get the address of a member function...

Dire Wolf
www.digitalfiends.com

Edited by - Dire.Wolf on November 9, 2001 6:25:34 PM

Edited by - Dire.Wolf on November 9, 2001 6:39:59 PM
[email=direwolf@digitalfiends.com]Dire Wolf[/email]
www.digitalfiends.com
Dactylos
Dactylos
For the voidFunction pointer-type to be able to hold pointers to methods you must declare it like:
  
typedef void (A::*voidFunction) ();

This becomes a pointer to a method in objects of class A. To set it you do something like:
  
voidFunction funPtr;
funPtr = A::functionA;

and to later call it you must have an object of class A, and call it for that object. e.g:
  
// either:

A a;
a.*funPtr();

// or:

A * pa = new A();
pa->*funPtr();

Hope things are clearer now (and I hope I didn''t make any big mistakes )
Roof Top Pew Wee
Roof Top Pew Wee
Dire.Wolf:
Hmmm, very interesting. One note: You said to change it to
&(classA::function). This is incorrect because when using the :: (scope resolution operator I believe) you have to have a class on the left side, not an object. So the correct method would be (&(A::voidfunction)).

However, your solution sets up a few problems.

1: Just because a function is in a class rather than outside of one, does it really chage it? I mean, ovbiously it does in my case, but isn''t there a way to just have a typedef for both functions in and outside of classes? And what if I have two classes that have a void function and I want to assign one or the other depending on some condition? Do I then have to have a typedef for the function in both class A and class B?

2: Also, this solution seems to point to the general function for the class A. But what the function that you are pointing to does work with members of the specific class. Example:

class A
{public:
int x;
void functionA(){x++;}
};

Now say that you have 3 instances of class A like this:

A classA1;
A classA2;
A classA3;

When you set the function in class B equal to A::functionA, well, how would the compiler know which x to add? classA1.x, classA2.x, or classA3.x?

--Vic--
Dire.Wolf
Dire.Wolf
Roof Top Pew Wee,

No to set a member function you use the scope-resolution operator to access the member function:

typedef void (A::*memberFunc)();

memberFunc m = &A::SomeActualFunc;

Then to call the function you must hold an object reference and call it using the pointer to member operator:

A* a = new A;
memberFunc m = &A::SomeActualFunc;

(a->*m)();

delete a;

That is all there is to it.

Remember all you are doing is passing the address of a function. You aren't passing an instance of that function because there is no such thing.





Dire Wolf
www.digitalfiends.com

Edited by - Dire.Wolf on November 9, 2001 6:56:46 PM
[email=direwolf@digitalfiends.com]Dire Wolf[/email]
www.digitalfiends.com
Oluseyi
Oluseyi
quote:
Original post by Roof Top Pew Wee
Dire.Wolf:
Hmmm, very interesting. One note: You said to change it to
&(classA::function). This is incorrect because when using the :: (scope resolution operator I believe) you have to have a class on the left side, not an object. So the correct method would be (&(A::voidfunction)).

Semantics. He uses classA as a single identifier for the class name; you use A.

quote:
1: Just because a function is in a class rather than outside of one, does it really chage it? I mean, ovbiously it does in my case, but isn''t there a way to just have a typedef for both functions in and outside of classes? And what if I have two classes that have a void function and I want to assign one or the other depending on some condition? Do I then have to have a typedef for the function in both class A and class B?

In order, yes, no, yes.

Yes, having a function in a class changes its defintion to only be valid relative to that class. No, you can''t just have a function pointer for all types of classes (unless they all inherit from a base class, but in such a case virtual functions are a better solution). yes, you have to have separate typedefs for class A and class B.

quote:
When you set the function in class B equal to A::functionA, well, how would the compiler know which x to add? classA1.x, classA2.x, or classA3.x?

Whichever object it is called relative to. Try it and be amazed.



I wanna work for Microsoft!
Roof Top Pew Wee
Roof Top Pew Wee
Dactylos:
I see. Your code seems to work, but I have a question:

Since I am putting the function in the classB, how would I call it? Would I have to go like this:
classA.(classB.functionPointer)(); ?

That seems kinda pointless. I mean, if I wanted to call the function from class A, I could just do it directly from A, instead of a big circle like that.

I could also include a classA inside classB so it'd be like:

classB.classA.(functionPointer)(); but again, that seems like too much to be doing. Are these the only two ways I could do it?

--Vic--

Edited by - Roof Top Pew Wee on November 9, 2001 6:53:21 PM
Dactylos
Dactylos
quote:
Original post by Roof Top Pew Wee
1: Just because a function is in a class rather than outside of one, does it really chage it?


Yes, functions outside of classes and non-static methods have different calling-conventions
quote:

I mean, ovbiously it does in my case, but isn''t there a way to just have a typedef for both functions in and outside of classes?


Not really (unless the method in the class is static, but that seems to not be such a good option for you).
quote:

And what if I have two classes that have a void function and I want to assign one or the other depending on some condition? Do I then have to have a typedef for the function in both class A and class B?


Yes you''ll probably need two different typedefs, unless both classes inherits some base class and you can typedef a pointer to a method in that class.
quote:

2: Also, this solution seems to point to the general function for the class A. But what the function that you are pointing to does work with members of the specific class. Example:

class A
{public:
int x;
void functionA(){x++;}
};

Now say that you have 3 instances of class A like this:

A classA1;
A classA2;
A classA3;

When you set the function in class B equal to A::functionA, well, how would the compiler know which x to add? classA1.x, classA2.x, or classA3.x?


Basically you need an object to ''apply'' the method to. Look at my previous post for an example.
Dactylos
Dactylos
Looks like everybody is replying at the same time
Dire.Wolf
Dire.Wolf
quote:

2: Also, this solution seems to point to the general function for the class A. But what the function that you are pointing to does work with members of the specific class. Example:

class A
{public:
int x;
void functionA(){x++;}
};

Now say that you have 3 instances of class A like this:

A classA1;
A classA2;
A classA3;

When you set the function in class B equal to A::functionA, well, how would the compiler know which x to add? classA1.x, classA2.x, or classA3.x?




To answer your question, you must realize that in order to call a member function via a member function pointer you *must* have a valid object reference (unless of course that member function is static.)

So once again:

B b;

b.setFunction(&A::functionA);
b.CallFunctionA(&classA1);
b.CallFunctionA(&classA2);
b.CallFunctionA(&classA3);

CallFunctionA would look something like:

void B::CallFunctionA(A* p)
{
(p->*functionPointer)();
}

Therefore there is no ambiguity for the compiler.

Just remember, for non-static member functions, you are invoking the member function using a member function pointer and the call through pointer to member operator.



Dire Wolf
www.digitalfiends.com

Edited by - Dire.Wolf on November 9, 2001 6:55:03 PM
[email=direwolf@digitalfiends.com]Dire Wolf[/email]
www.digitalfiends.com
Roof Top Pew Wee
Roof Top Pew Wee
All I can say is WOW. I had no clue that my problem would be so complex, or at least I had no clue this was the solution. I wanna thank all of you guys for helpin me out. I''m going to have to stare at the code for a while, and then apply it to my GUI, which will be quite the challenge.

--Vic--
Dire.Wolf
Dire.Wolf
The question is what are you trying to accomplish with member function pointers that can''t be done with inheritance and overloading?

Give us an example if you can.

Glad to see you have it sorted out somewhat.

Dire Wolf
www.digitalfiends.com
[email=direwolf@digitalfiends.com]Dire Wolf[/email]
www.digitalfiends.com
Dactylos
Dactylos
quote:
Original post by Roof Top Pew Wee
Dactylos:
I see. Your code seems to work, but I have a question:

Since I am putting the function in the classB, how would I call it? Would I have to go like this:
classA.(classB.functionPointer)(); ?


Basically yes (though your syntax is wrong, you must use the ''.*'' or ''->*'' operators). You should store both a pointer to a method and an object to apply that method to in B.
quote:

That seems kinda pointless. I mean, if I wanted to call the function from class A, I could just do it directly from A, instead of a big circle like that.


Well, why are you doing this. If you don''t see any gain to it perhaps you should try to accomplish whatever you''re doing some other way.
quote:

I could also include a classA inside classB so it''d be like:

classB.classA.(functionPointer)(); but again, that seems like too much to be doing. Are these the only two ways I could do it?


Well, without knowing what you''re trying to accomplish I can''t really answer that, but regarding method-pointers those are basically the only ways to do it (I would say those two ways are one and the same though).
Roof Top Pew Wee
Roof Top Pew Wee
Ok, here''s the purpose of the question. I am programming games, obviously, and I didn''t want to learn Windows programming, so I created my own GUI. Well, I am currently working on a File menu. Like the one you click on and get Open, Close, Save, Exit, and so on. I have created a function to this menu that works like this.
void addItem(char* commandToAdd, plainFunction doThisFunction)

So you would call it like this:

fileMenu.addItem("Save", &WHATEVERFUNCTION)

Well, I have already created a save/load dialog window. And it has an activate function. So what I''d wanna do is be able to do something to this effect:

fileMenu.addItem("Save", &(saveLoadDialog.activate) )

I now realize that the correct method is to do:

fileMenu.addItem("Save", &(fileBox::activate), &saveLoadDialog);

So I''m going to have to create a different version for when a member function is passed so that the function also takes the address of the class to use when calling the function.

I''m thinking I have it down now, but if you guys see any problems, don''t hesitate to tell me. Thanks VERY MUCH!
--Vic--
Dactylos
Dactylos
Dire.Wolf,
Yeah, we seem to be posting at the same time
Shannon Barber
Shannon Barber
Read about the "Observer" or "Listener" pattern
The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
Roof Top Pew Wee
Roof Top Pew Wee
Magmai Kai Holmlor:
Besides your post, I have no clue where to read about it.
Actually, I did look up Observer in the help, but it's all about Java. I don't know anything about Java.

--Vic--

Edited by - Roof Top Pew Wee on November 9, 2001 7:35:08 PM

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.