Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. Function Pointer

Function Pointer

Scheduled Pinned Locked Moved C / C++ / MFC
wpftutorialquestion
12 Posts 6 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • D Offline
    D Offline
    dehseth
    wrote on last edited by
    #1

    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();
    

    ...

    Richard Andrew x64R S L 4 Replies Last reply
    0
    • D dehseth

      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();
      

      ...

      Richard Andrew x64R Offline
      Richard Andrew x64R Offline
      Richard Andrew x64
      wrote on last edited by
      #2

      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.

      1 Reply Last reply
      0
      • D dehseth

        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();
        

        ...

        S Offline
        S Offline
        Stuart Dootson
        wrote on last edited by
        #3

        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

        D Richard Andrew x64R R 3 Replies Last reply
        0
        • S Stuart Dootson

          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

          D Offline
          D Offline
          dehseth
          wrote on last edited by
          #4

          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... :(

          S C 2 Replies Last reply
          0
          • D dehseth

            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... :(

            S Offline
            S Offline
            Stuart Dootson
            wrote on last edited by
            #5

            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

            1 Reply Last reply
            0
            • D dehseth

              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();
              

              ...

              L Offline
              L Offline
              Lost User
              wrote on last edited by
              #6

              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.

              L 1 Reply Last reply
              0
              • L Lost User

                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.

                L Offline
                L Offline
                Lost User
                wrote on last edited by
                #7

                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 this method(&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.

                1 Reply Last reply
                0
                • S Stuart Dootson

                  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

                  Richard Andrew x64R Offline
                  Richard Andrew x64R Offline
                  Richard Andrew x64
                  wrote on last edited by
                  #8

                  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))();

                  ?

                  S 1 Reply Last reply
                  0
                  • Richard Andrew x64R Richard Andrew x64

                    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))();

                    ?

                    S Offline
                    S Offline
                    Stuart Dootson
                    wrote on last edited by
                    #9

                    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

                    1 Reply Last reply
                    0
                    • D dehseth

                      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... :(

                      C Offline
                      C Offline
                      CPallini
                      wrote on last edited by
                      #10

                      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]

                      1 Reply Last reply
                      0
                      • D dehseth

                        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();
                        

                        ...

                        L Offline
                        L Offline
                        Lost User
                        wrote on last edited by
                        #11

                        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 F

                        R 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

                        1 Reply Last reply
                        0
                        • S Stuart Dootson

                          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

                          R Offline
                          R Offline
                          Rajesh R Subramanian
                          wrote on last edited by
                          #12

                          Very nicely written, Stuart. My 5 for you. :)

                          It is a crappy thing, but it's life -^ Carlo Pallini

                          1 Reply Last reply
                          0
                          Reply
                          • Reply as topic
                          Log in to reply
                          • Oldest to Newest
                          • Newest to Oldest
                          • Most Votes


                          • Login

                          • Don't have an account? Register

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • World
                          • Users
                          • Groups