Function Pointer
-
Hey everybody, Let's see if I have this code:
class R
{
public:
typedef void (*Method)();
Method onClick;void Do() { (\*onClick) (); }
};
void ok()
{
printf("OK\r\n");
}int _tmain(int argc, _TCHAR* argv[])
{
printf("main\n");R r; r.onClick = &ok; r.Do();
...
Just runs. :thumbsup: Function pointer works.. But if I try to point a NON-STATIC function of a class.. well cant do that! :doh: I need to pass class instance also.. :) But dunno if there's a way to do that without templates. :| So any idea how to do that without using template? :) To make it clear:
class A
{
public:
void run(void);
};class R
{
public:
typedef void (*Method)();
Method onClick;void Do() { (\*onClick) (); }
};
void ok()
{
printf("OK\r\n");
}int _tmain(int argc, _TCHAR* argv[])
{
printf("main\n");A a; R r; r.onClick = &a.run; //wont work r.Do();
...
-
Hey everybody, Let's see if I have this code:
class R
{
public:
typedef void (*Method)();
Method onClick;void Do() { (\*onClick) (); }
};
void ok()
{
printf("OK\r\n");
}int _tmain(int argc, _TCHAR* argv[])
{
printf("main\n");R r; r.onClick = &ok; r.Do();
...
Just runs. :thumbsup: Function pointer works.. But if I try to point a NON-STATIC function of a class.. well cant do that! :doh: I need to pass class instance also.. :) But dunno if there's a way to do that without templates. :| So any idea how to do that without using template? :) To make it clear:
class A
{
public:
void run(void);
};class R
{
public:
typedef void (*Method)();
Method onClick;void Do() { (\*onClick) (); }
};
void ok()
{
printf("OK\r\n");
}int _tmain(int argc, _TCHAR* argv[])
{
printf("main\n");A a; R r; r.onClick = &a.run; //wont work r.Do();
...
There is a difference between a regular function pointer as you have declared in R, and a "pointer to a member function," which is what you want in the last code example. The syntax is quite cryptic, and I don't recall what it is, but if you search for "pointer to member function," I'm sure you'll come up with it.
-
Hey everybody, Let's see if I have this code:
class R
{
public:
typedef void (*Method)();
Method onClick;void Do() { (\*onClick) (); }
};
void ok()
{
printf("OK\r\n");
}int _tmain(int argc, _TCHAR* argv[])
{
printf("main\n");R r; r.onClick = &ok; r.Do();
...
Just runs. :thumbsup: Function pointer works.. But if I try to point a NON-STATIC function of a class.. well cant do that! :doh: I need to pass class instance also.. :) But dunno if there's a way to do that without templates. :| So any idea how to do that without using template? :) To make it clear:
class A
{
public:
void run(void);
};class R
{
public:
typedef void (*Method)();
Method onClick;void Do() { (\*onClick) (); }
};
void ok()
{
printf("OK\r\n");
}int _tmain(int argc, _TCHAR* argv[])
{
printf("main\n");A a; R r; r.onClick = &a.run; //wont work r.Do();
...
A non-static method pointer is the same as any function pointer that needs parameters - you need to tell the caller what those parameters are. So, you could do this:
class R
{
public:
typedef void (A::*Method)();
struct MethodCall { Method fn; A obj; };
MethodCall onClick;void Do() { Method m = onClick.fn; A& a = onClick.obj; ((a).\*(m))(); }
};
int main(int argc, char* argv[])
{A a; R r; r.onClick.obj = a; r.onClick.fn = &A::run; //wont work r.Do();
}
But then if you wanted to use
ok
as a handler as well, you'd need to add a separate data member for that. Getting around all that is the raison d'etre for Boost.Function[^] (also in std::tr1::function in VC2008, I believe). With that (and a smidgen of Boost.Lambda[^]), I'd write your onClick handler like this:#include <iostream>
#include <boost/function.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>class A
{
public:
void run(void) { std::cout << "A::run\n"; }
};class R
{
public:
boost::function<void()> onClick;void Do()
{
onClick();
}
};void ok()
{
std::cout << "ok\n";
}int main(int argc, char* argv[])
{A a;
R r;
r.onClick = ok;
r.Do();
using namespace boost::lambda;
r.onClick = bind(&A::run, var(a));
r.Do();
}If you then want multiple handlers, Boost.Signals[^] is very useful as well! [edit]It would be remiss of me not to point out that Boost.Function is compatible with the STL binders such as mem_fun[^] - but as Boost.Lambda is so much cooler, I hope you'll forgive me :-)[/edit]
Java, Basic, who cares - it's all a bunch of tree-hugging hi
-
A non-static method pointer is the same as any function pointer that needs parameters - you need to tell the caller what those parameters are. So, you could do this:
class R
{
public:
typedef void (A::*Method)();
struct MethodCall { Method fn; A obj; };
MethodCall onClick;void Do() { Method m = onClick.fn; A& a = onClick.obj; ((a).\*(m))(); }
};
int main(int argc, char* argv[])
{A a; R r; r.onClick.obj = a; r.onClick.fn = &A::run; //wont work r.Do();
}
But then if you wanted to use
ok
as a handler as well, you'd need to add a separate data member for that. Getting around all that is the raison d'etre for Boost.Function[^] (also in std::tr1::function in VC2008, I believe). With that (and a smidgen of Boost.Lambda[^]), I'd write your onClick handler like this:#include <iostream>
#include <boost/function.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>class A
{
public:
void run(void) { std::cout << "A::run\n"; }
};class R
{
public:
boost::function<void()> onClick;void Do()
{
onClick();
}
};void ok()
{
std::cout << "ok\n";
}int main(int argc, char* argv[])
{A a;
R r;
r.onClick = ok;
r.Do();
using namespace boost::lambda;
r.onClick = bind(&A::run, var(a));
r.Do();
}If you then want multiple handlers, Boost.Signals[^] is very useful as well! [edit]It would be remiss of me not to point out that Boost.Function is compatible with the STL binders such as mem_fun[^] - but as Boost.Lambda is so much cooler, I hope you'll forgive me :-)[/edit]
Java, Basic, who cares - it's all a bunch of tree-hugging hi
OK I forgot to mention the most important thing :-\ I want to point my function at run time. I mean it should be any kind of function pointer which accept this. So this is not acceptable for me &A::run... I do not need boost for that (this will do the job if I already knew the class):
class SomeClass;
typedef void (SomeClass::* SomeClassFunction)(void);
void Invoke(SomeClass *pClass, SomeClassFunction funcptr) {
(pClass->*funcptr)(); };Seems like there's no way... :(
-
OK I forgot to mention the most important thing :-\ I want to point my function at run time. I mean it should be any kind of function pointer which accept this. So this is not acceptable for me &A::run... I do not need boost for that (this will do the job if I already knew the class):
class SomeClass;
typedef void (SomeClass::* SomeClassFunction)(void);
void Invoke(SomeClass *pClass, SomeClassFunction funcptr) {
(pClass->*funcptr)(); };Seems like there's no way... :(
dehseth wrote:
I do not need boost for that
Maybe not - but it sure makes things a lot easier :-) And not just for function pointers!!
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
-
Hey everybody, Let's see if I have this code:
class R
{
public:
typedef void (*Method)();
Method onClick;void Do() { (\*onClick) (); }
};
void ok()
{
printf("OK\r\n");
}int _tmain(int argc, _TCHAR* argv[])
{
printf("main\n");R r; r.onClick = &ok; r.Do();
...
Just runs. :thumbsup: Function pointer works.. But if I try to point a NON-STATIC function of a class.. well cant do that! :doh: I need to pass class instance also.. :) But dunno if there's a way to do that without templates. :| So any idea how to do that without using template? :) To make it clear:
class A
{
public:
void run(void);
};class R
{
public:
typedef void (*Method)();
Method onClick;void Do() { (\*onClick) (); }
};
void ok()
{
printf("OK\r\n");
}int _tmain(int argc, _TCHAR* argv[])
{
printf("main\n");A a; R r; r.onClick = &a.run; //wont work r.Do();
...
There are three reasons you can't do this the way you think it should work: First &a.run is not the right way of getting a pointer to a class function, it is &A::run. Second you can't convert from your Method type above to &A::run. Third you can't execute a non-static method of a class unless you have an instance of that class (and this looks quite normal because we have to know which instance it is whose method we want to execute, non-static method have no meaning without an instance) This is how you would write it using your way of thinking:
class A{
public: void run(void);
};class R{
public:typedef void (A::\*Method)(); Method onClick; void Do(A\* a) { (a->\*onClick) (); }
};
int _tmain(int argc, _TCHAR* argv[])
{
printf("main\n");
A a;
R r;
r.onClick = &A::run;
r.Do(&a);...
}As you can see however there is nothing much useful to generalize, so the above code is just hiding something for no apparent reason. But you needed an answer :) You can't create a pointer for one class non-static method and use it as a pointer to another class method.
-
There are three reasons you can't do this the way you think it should work: First &a.run is not the right way of getting a pointer to a class function, it is &A::run. Second you can't convert from your Method type above to &A::run. Third you can't execute a non-static method of a class unless you have an instance of that class (and this looks quite normal because we have to know which instance it is whose method we want to execute, non-static method have no meaning without an instance) This is how you would write it using your way of thinking:
class A{
public: void run(void);
};class R{
public:typedef void (A::\*Method)(); Method onClick; void Do(A\* a) { (a->\*onClick) (); }
};
int _tmain(int argc, _TCHAR* argv[])
{
printf("main\n");
A a;
R r;
r.onClick = &A::run;
r.Do(&a);...
}As you can see however there is nothing much useful to generalize, so the above code is just hiding something for no apparent reason. But you needed an answer :) You can't create a pointer for one class non-static method and use it as a pointer to another class method.
The reason this is so is that method does not know anything about the instance that calls it. The instance pointer (this) is resolved at the moment of method call. This:
C c; c.method();
is executed using always one and the same address of the method but the class instance pointer ( this-> ) is passed for example as the first hidden parameter (which is hidden from us) like thismethod(&c)
or the instance pointer (&c) is moved into ECX register first and then method() is called where each this-> is then referred by the content of ECX. You can't avoid this problem even with boost or any other library. -
A non-static method pointer is the same as any function pointer that needs parameters - you need to tell the caller what those parameters are. So, you could do this:
class R
{
public:
typedef void (A::*Method)();
struct MethodCall { Method fn; A obj; };
MethodCall onClick;void Do() { Method m = onClick.fn; A& a = onClick.obj; ((a).\*(m))(); }
};
int main(int argc, char* argv[])
{A a; R r; r.onClick.obj = a; r.onClick.fn = &A::run; //wont work r.Do();
}
But then if you wanted to use
ok
as a handler as well, you'd need to add a separate data member for that. Getting around all that is the raison d'etre for Boost.Function[^] (also in std::tr1::function in VC2008, I believe). With that (and a smidgen of Boost.Lambda[^]), I'd write your onClick handler like this:#include <iostream>
#include <boost/function.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>class A
{
public:
void run(void) { std::cout << "A::run\n"; }
};class R
{
public:
boost::function<void()> onClick;void Do()
{
onClick();
}
};void ok()
{
std::cout << "ok\n";
}int main(int argc, char* argv[])
{A a;
R r;
r.onClick = ok;
r.Do();
using namespace boost::lambda;
r.onClick = bind(&A::run, var(a));
r.Do();
}If you then want multiple handlers, Boost.Signals[^] is very useful as well! [edit]It would be remiss of me not to point out that Boost.Function is compatible with the STL binders such as mem_fun[^] - but as Boost.Lambda is so much cooler, I hope you'll forgive me :-)[/edit]
Java, Basic, who cares - it's all a bunch of tree-hugging hi
Stuart, Excellent answer, as usual. I have one question: You gave the actual function call as:
((a).*(m))();
Why do we need the parenthesis around
a
? Why can we not write:(a.*(m))();
?
-
Stuart, Excellent answer, as usual. I have one question: You gave the actual function call as:
((a).*(m))();
Why do we need the parenthesis around
a
? Why can we not write:(a.*(m))();
?
I can never remember the syntax you need for a member function pointer call - so I kept putting in brackets until it compiled :-) I just happened to put the brackets round
a
before the ones that really mattered!! [edit]Richard Andrew x64 wrote:
Excellent answer, as usual
PS - thank you for the compliment - I tries me best, Guvnor! [/edit]
Java, Basic, who cares - it's all a bunch of tree-hugging hippy cr*p
modified on Monday, March 2, 2009 4:11 PM
-
OK I forgot to mention the most important thing :-\ I want to point my function at run time. I mean it should be any kind of function pointer which accept this. So this is not acceptable for me &A::run... I do not need boost for that (this will do the job if I already knew the class):
class SomeClass;
typedef void (SomeClass::* SomeClassFunction)(void);
void Invoke(SomeClass *pClass, SomeClassFunction funcptr) {
(pClass->*funcptr)(); };Seems like there's no way... :(
You don't like polymorphism, do you (i.e. why do you want to do that, cannot you find an OOP way to accomplish your needs)? :)
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler. -- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong. -- Iain Clarke
[My articles] -
Hey everybody, Let's see if I have this code:
class R
{
public:
typedef void (*Method)();
Method onClick;void Do() { (\*onClick) (); }
};
void ok()
{
printf("OK\r\n");
}int _tmain(int argc, _TCHAR* argv[])
{
printf("main\n");R r; r.onClick = &ok; r.Do();
...
Just runs. :thumbsup: Function pointer works.. But if I try to point a NON-STATIC function of a class.. well cant do that! :doh: I need to pass class instance also.. :) But dunno if there's a way to do that without templates. :| So any idea how to do that without using template? :) To make it clear:
class A
{
public:
void run(void);
};class R
{
public:
typedef void (*Method)();
Method onClick;void Do() { (\*onClick) (); }
};
void ok()
{
printf("OK\r\n");
}int _tmain(int argc, _TCHAR* argv[])
{
printf("main\n");A a; R r; r.onClick = &a.run; //wont work r.Do();
...
If you are ready to make a slight design change this is what you can do and to get something fairly useful
class T
{
public:
virtual void run() = 0; // this does not have to be abstract if you don't like, but it saves some bits
virtual void run1() = 0; // another possible event
};class A : public T
{
public:
void run(){ // A version
};void run1(){ // A version };
};
class F : public T
{
public:
void run(){ // F version
};void run1(){ // F version };
};
class R{
public:typedef void (T::\*Method)(); // general abstract method used, it can point to any method without parameters Method onClick; void Do(T\* t) // abstract type used { (t->\*onClick)(); }
};
int _tmain(int argc, _TCHAR* argv[])
{
A a; // create object A
F f; // create object FR r; r.onClick = &T::run; // set one general event // now different type passed leads to different call r.Do(&a); // A::run called r.Do(&f); // F::run called r.onClick = &T::run1; // set another general event // again different type passed leads to different call r.Do(&a); // A::run1 called r.Do(&f); // F::run1 called ...
modified on Monday, March 2, 2009 5:57 PM
-
A non-static method pointer is the same as any function pointer that needs parameters - you need to tell the caller what those parameters are. So, you could do this:
class R
{
public:
typedef void (A::*Method)();
struct MethodCall { Method fn; A obj; };
MethodCall onClick;void Do() { Method m = onClick.fn; A& a = onClick.obj; ((a).\*(m))(); }
};
int main(int argc, char* argv[])
{A a; R r; r.onClick.obj = a; r.onClick.fn = &A::run; //wont work r.Do();
}
But then if you wanted to use
ok
as a handler as well, you'd need to add a separate data member for that. Getting around all that is the raison d'etre for Boost.Function[^] (also in std::tr1::function in VC2008, I believe). With that (and a smidgen of Boost.Lambda[^]), I'd write your onClick handler like this:#include <iostream>
#include <boost/function.hpp>
#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>class A
{
public:
void run(void) { std::cout << "A::run\n"; }
};class R
{
public:
boost::function<void()> onClick;void Do()
{
onClick();
}
};void ok()
{
std::cout << "ok\n";
}int main(int argc, char* argv[])
{A a;
R r;
r.onClick = ok;
r.Do();
using namespace boost::lambda;
r.onClick = bind(&A::run, var(a));
r.Do();
}If you then want multiple handlers, Boost.Signals[^] is very useful as well! [edit]It would be remiss of me not to point out that Boost.Function is compatible with the STL binders such as mem_fun[^] - but as Boost.Lambda is so much cooler, I hope you'll forgive me :-)[/edit]
Java, Basic, who cares - it's all a bunch of tree-hugging hi
Very nicely written, Stuart. My 5 for you. :)
It is a crappy thing, but it's life -^ Carlo Pallini