C++ 设置指向非静态成员函数的指针

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15035905/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 18:54:51  来源:igfitidea点击:

Setting a pointer to a non-static member function

c++

提问by Part Time User

I'm trying to setup a function pointer that is set during execution based on a set of user parameters. I would like to have the function pointer point to a non-static member function but I can't find how to do it.

我正在尝试根据一组用户参数设置在执行期间设置的函数指针。我想让函数指针指向一个非静态成员函数,但我找不到如何去做。

The examples I've seen say this can only be done with static member function only or use global variables in straight C.

我见过的例子说这只能用静态成员函数来完成,或者在直接 C 中使用全局变量。

A simplified example follows:

一个简化的例子如下:

    class CA
    {
    public:
        CA(void) {};
        ~CA(void) {};
        void setA(double x) {a = x; };
        void setB(double x) {b = x; };

        double getA(const double x) {return x*a; };
        double getB(const double x) {return x*b; };

        void print(double f(const double), double x) {
            char cTemp[256];
            sprintf_s(cTemp, "Value = %f", f(x));
            std::cout << cTemp;
        };

    private:
        double a, b;
    };

The implementation part is

实现部分是

CA cA;
cA.setA(1.0);
cA.setB(2.0);

double (*p)(const double);

if(true) {
    p = &cA.getA;  //'&' : illegal operation on bound member function expression
} else {
    p = cA.getB;  //'CA::getB': function call missing argument list; use '&CA::getB' to create a pointer to member
                  //'=' : cannot convert from 'double (__thiscall CA::* )(const double)' to 'double (__cdecl *)(const double)'
}

cA.print(p, 3.0);

So how do I get p to point to either 'getA' or 'getB' so that it is still useable by 'print'.

那么我如何让 p 指向 'getA' 或 'getB' 以便它仍然可以被 'print' 使用。

From what I have seen, the suggestions are to use boost or std::bind but I've had no experience with either of these. I'm hoping that I don't need to dive into these and that I'm just missing something.

从我所见,建议是使用 boost 或 std::bind 但我对这两种方法都没有经验。我希望我不需要深入研究这些,我只是错过了一些东西。

Compiler MSVC++ 2008

编译器 MSVC++ 2008

回答by Andy Prowl

Don't forget that a member function accepts an implicit thisparameter: therefore, a member function accepting a doublecan't be the same thing as a non-member (free) function accepting a double.

不要忘记成员函数接受一个隐式this参数:因此,接受 a 的成员函数double不能与接受 a的非成员(自由)函数相同double

// OK for global functions
double (*p)(const double);

// OK for member functions
double (CA:*p)(const double);

Also the way you invokethem is different. First of all, with member functions, you need an object to invoke them on (its address will eventually be bound to the thispointer in the function call). Second, you need to use the .*operator (or the ->*operator if you are performing the call through a pointer):

调用它们的方式也不同。首先,对于成员函数,您需要一个对象来调用它们(它的地址最终将绑定到this函数调用中的指针)。其次,您需要使用.*运算符(->*如果您通过指针执行调用,则使用运算符):

p = &CA::getA;
CA cA;
(cA.*p)();

Consistently, you will have to change your definition of function print():

始终如一地,您将不得不更改 function 的定义print()

    #include <iostream>

    void print(double (CA::*f)(const double), double x) 
    {
        // Rather use the C++ I/O Library if you can...
        std::cout << "Value = " << (this->*f)(x);
    };

So finally, this is how you should rewrite your main()function:

所以最后,这就是你应该如何重写你的main()函数:

int main()
{
    CA cA;
    cA.setA(1.0);
    cA.setB(2.0);

    double (CA::*p)(const double);

    if (true) // Maybe use some more exciting condition :-)
    {
        p = &CA::getA;
    } 
    else {
        p = &CA::getB;
    }

    cA.print(p, 3.0);
}

回答by Johnsyweb

Compilation Issue

编译问题

This answer focuses on the compilation issue presented in the question.I would not recommend implementing this as a solution.

该答案侧重于问题中提出的编译问题。我不建议将此作为解决方案实施。

Pointers to member functions are best dealt with with typedefs and a macro.

最好用typedefs 和宏处理指向成员函数的指针。

Here's the macro for calling a member function:

这是调用成员函数的宏:

#define CALL_MEMBER_FN(object, ptrToMember)  ((object).*(ptrToMember))

Source:[33.6] How can I avoid syntax errors when calling a member function using a pointer-to-member-function?, C++ FAQ.

来源:[33.6] 使用指向成员函数的指针调用成员函数时,如何避免语法错误?, C++ 常见问题解答

This saves you having to remember the ugly (object).*(ptrToMember)syntax any time you wish to call a member function by pointer.

这使您在(object).*(ptrToMember)任何时候希望通过指针调用成员函数时都不必记住丑陋的语法。

In your class, declare a typedefcalled CAGetter, this will make variable declaration much simpler:

在您的class, 声明一个typedef被调用的CAGetter,这将使变量声明更简单:

class CA
{
public:    
    typedef double (CA::*CAGetter)(const double x);

Then you can declare your print()function quite simply:

然后你可以print()很简单地声明你的函数:

    void print(CAGetter f, double x)

The body is also simple, clear and concise:

正文也简洁明了,简洁明了:

    {
        std::cout << "value = " << CALL_MEMBER_FN(*this, f)(x) << '\n';
    }

Sample usage:

示例用法:

CA a;
a.setA(3.1);
a.setB(4.2);

// Using a variable...
CA::CAGetter p = &CA::getA;
a.print(p, 1);

// without a variable
a.print(&CA::getB, 1);

// Calling the functions from outside the class...
std::cout << "From outside (A): " << CALL_MEMBER_FN(a, p)(10) << std::endl;
std::cout << "From outside (B): " << CALL_MEMBER_FN(a, &CA::getB)(10) << std::endl;

Design Issue

设计问题

Passing a pointer to a member function into a method of an instance of the same class is a design smell (you wouldn't normally pass a member variable to a method, this is no different). There is not enough information in this question to address the underlying design issue but this problem could probably be solved with separate print()methods, a member variable or with inheritance and polymorphism.

将指向成员函数的指针传递给同一个类的实例的方法是一种设计味道(您通常不会将成员变量传递给方法,这没有什么不同)。这个问题没有足够的信息来解决底层设计问题,但这个问题可能可以通过单独的print()方法、成员变量或继承和多态来解决。

回答by Slava

You can either use pointer to method:

您可以使用指向方法的指针:

class CA
{
    public:
        typedef double (CA::*getter)( double );
        CA(void) {};
        ~CA(void) {};
        void setA(double x) {a = x; };
        void setB(double x) {b = x; };

        double getA(const double x) {return x*a; };
        double getB(const double x) {return x*b; };

        void print(getter f, double x) {
            char cTemp[256];
            sprintf(cTemp, "Value = %f", (this->*f)(x));
            std::cout << cTemp;
        };

    private:
        double a, b;
};

int main()
{
    CA cA;
    cA.setA(1.0);
    cA.setB(2.0);

    CA::getter p;

    if(true) {
            p = &CA::getA;  
    } else {
            p = &CA::getB; 
    cA.print( p, 3.0 );
}

Or use boost::bind

或者使用 boost::bind

class CA
{
    public:
        typedef boost::function<double( double )> getter;
        CA(void) {};
        ~CA(void) {};
        void setA(double x) {a = x; };
        void setB(double x) {b = x; };

        double getA(const double x) {return x*a; };
        double getB(const double x) {return x*b; };

        void print(getter f, double x) {
            char cTemp[256];
            sprintf(cTemp, "Value = %f", f(x));
            std::cout << cTemp;
        };

    private:
        double a, b;
};

int main()
{
    CA cA;
    cA.setA(1.0);
    cA.setB(2.0);

    CA::getter p;

    if(true) {
            p = boost::bind( &CA::getA, &cA, _1 );
    } else {
            p = boost::bind( &CA::getB, &cA, _1 );
    }
    cA.print( p, 3.0 );
}