Calling C++ class methods via a function pointer

前端 未结 10 835
醉酒成梦
醉酒成梦 2020-11-22 06:47

How do I obtain a function pointer for a class member function, and later call that member function with a specific object? I’d like to write:

class Dog : A         


        
相关标签:
10条回答
  • 2020-11-22 07:05

    Read this for detail :

    // 1 define a function pointer and initialize to NULL
    
    int (TMyClass::*pt2ConstMember)(float, char, char) const = NULL;
    
    // C++
    
    class TMyClass
    {
    public:
       int DoIt(float a, char b, char c){ cout << "TMyClass::DoIt"<< endl; return a+b+c;};
       int DoMore(float a, char b, char c) const
             { cout << "TMyClass::DoMore" << endl; return a-b+c; };
    
       /* more of TMyClass */
    };
    pt2ConstMember = &TMyClass::DoIt; // note: <pt2Member> may also legally point to &DoMore
    
    // Calling Function using Function Pointer
    
    (*this.*pt2ConstMember)(12, 'a', 'b');
    
    0 讨论(0)
  • 2020-11-22 07:07

    A function pointer to a class member is a problem that is really suited to using boost::function. Small example:

    #include <boost/function.hpp>
    #include <iostream>
    
    class Dog 
    {
    public:
       Dog (int i) : tmp(i) {}
       void bark ()
       {
          std::cout << "woof: " << tmp << std::endl;
       }
    private:
       int tmp;
    };
    
    
    
    int main()
    {
       Dog* pDog1 = new Dog (1);
       Dog* pDog2 = new Dog (2);
    
       //BarkFunction pBark = &Dog::bark;
       boost::function<void (Dog*)> f1 = &Dog::bark;
    
       f1(pDog1);
       f1(pDog2);
    }
    
    0 讨论(0)
  • 2020-11-22 07:07

    To create a new object you can either use placement new, as mentioned above, or have your class implement a clone() method that creates a copy of the object. You can then call this clone method using a member function pointer as explained above to create new instances of the object. The advantage of clone is that sometimes you may be working with a pointer to a base class where you don't know the type of the object. In this case a clone() method can be easier to use. Also, clone() will let you copy the state of the object if that is what you want.

    0 讨论(0)
  • 2020-11-22 07:09

    Minimal runnable example

    main.cpp

    #include <cassert>
    
    class C {
        public:
            int i;
            C(int i) : i(i) {}
            int m(int j) { return this->i + j; }
    };
    
    int main() {
        // Get a method pointer.
        int (C::*p)(int) = &C::m;
    
        // Create a test object.
        C c(1);
        C *cp = &c;
    
        // Operator .*
        assert((c.*p)(2) == 3);
    
        // Operator ->*
        assert((cp->*p)(2) == 3);
    }
    

    Compile and run:

    g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
    ./main.out
    

    Tested in Ubuntu 18.04.

    You cannot change the order of the parenthesis or omit them. The following do not work:

    c.*p(2)
    c.*(p)(2)
    

    GCC 9.2 would fail with:

    main.cpp: In function ‘int main()’:
    main.cpp:19:18: error: must use ‘.*’ or ‘->*’ to call pointer-to-member function in ‘p (...)’, e.g. ‘(... ->* p) (...)’
       19 |     assert(c.*p(2) == 3);
          |
    

    C++11 standard

    .* and ->* are a single operators introduced in C++ for this purpose, and not present in C.

    C++11 N3337 standard draft:

    • 2.13 "Operators and punctuators" has a list of all operators, which contains .* and ->*.
    • 5.5 "Pointer-to-member operators" explains what they do
    0 讨论(0)
  • 2020-11-22 07:13

    I don't think anyone has explained here that one issue is that you need "member pointers" rather than normal function pointers.

    Member pointers to functions are not simply function pointers. In implementation terms, the compiler cannot use a simple function address because, in general, you don't know the address to call until you know which object to dereference for (think virtual functions). You also need to know the object in order to provide the this implicit parameter, of course.

    Having said that you need them, now I'll say that you really need to avoid them. Seriously, member pointers are a pain. It is much more sane to look at object-oriented design patterns that achieve the same goal, or to use a boost::function or whatever as mentioned above - assuming you get to make that choice, that is.

    If you are supplying that function pointer to existing code, so you really need a simple function pointer, you should write a function as a static member of the class. A static member function doesn't understand this, so you'll need to pass the object in as an explicit parameter. There was once a not-that-unusual idiom along these lines for working with old C code that needs function pointers

    class myclass
    {
      public:
        virtual void myrealmethod () = 0;
    
        static void myfunction (myclass *p);
    }
    
    void myclass::myfunction (myclass *p)
    {
      p->myrealmethod ();
    }
    

    Since myfunction is really just a normal function (scope issues aside), a function pointer can be found in the normal C way.

    EDIT - this kind of method is called a "class method" or a "static member function". The main difference from a non-member function is that, if you reference it from outside the class, you must specify the scope using the :: scope resolution operator. For example, to get the function pointer, use &myclass::myfunction and to call it use myclass::myfunction (arg);.

    This kind of thing is fairly common when using the old Win32 APIs, which were originally designed for C rather than C++. Of course in that case, the parameter is normally LPARAM or similar rather than a pointer, and some casting is needed.

    0 讨论(0)
  • 2020-11-22 07:13
    typedef void (Dog::*memfun)();
    memfun doSomething = &Dog::bark;
    ....
    (pDog->*doSomething)(); // if pDog is a pointer
    // (pDog.*doSomething)(); // if pDog is a reference
    
    0 讨论(0)
提交回复
热议问题