Archived

This topic is now archived and is closed to further replies.

Roof Top Pew Wee

Function pointers pointing to class functions?

Recommended Posts

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--

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
i dont think you need the &..

every piece of function pointer code ive ever written has never needed it. i could be wrong though.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
i dont think you need the &..

every piece of function pointer code ive ever written has never needed it. i could be wrong though.

Share this post


Link to post
Share on other sites
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--

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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 )

Share this post


Link to post
Share on other sites
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--

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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!

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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--

Share this post


Link to post
Share on other sites
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).

Share this post


Link to post
Share on other sites
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--

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
Roof Top, having looked at your description of what your trying to achieve I''ll recommend you use virtual functions and message maps. We''ll take a page from MFC:
Have each menu item generate a message (essentially have the messages be enumerated integers) and have each class maintain a message map. In response to the message, let the class call one of its functions which has been registered as the message handler.


The beauty of this method is that it is extensible, and the core mechanism can be implemented in a single base class from which all other UI classes derive.



I wanna work for Microsoft!

Share this post


Link to post
Share on other sites
My understanding of message maps is this: You have a global variable which every loop, you set to 0. Then you have #defines for everything that could happen. Then you test your objects (the various GUI objects in my case) and if there is a value, then go through a switch on this global message variable and execute whatever is the appropriate code. I don''t know if this is what you are actually referring to, but I doubt I will use this: I have written MANY lines of code on this GUI, and it all is working fine without message maps. I am simply adding something to the function of my GUI, and I highly doubt that I will change my whole approach for one thing. If it ain''t broke, don''t fix it . Thanks for the suggestion, guys, but as far as reinventing my GUI, I think I''ll just stick to the old method. This function pointer stuff seems to be working just fine for me.

--Vic--

Share this post


Link to post
Share on other sites