简体   繁体   English

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

[英]Setting a pointer to a non-static member function

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. 我见过的例子说这只能用静态成员函数来完成,或者直接使用全局变量。

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. 从我所看到的,建议是使用boost或std :: bind但我没有任何经验。 I'm hoping that I don't need to dive into these and that I'm just missing something. 我希望我不需要深入了解这些,而我只是错过了一些东西。

Compiler MSVC++ 2008 编译器MSVC ++ 2008

Don't forget that a member function accepts an implicit this parameter: therefore, a member function accepting a double can't be the same thing as a non-member (free) function accepting a double . 不要忘记,成员函数接受一个隐含的this参数:因此,一个成员函数接受double不能是相同的东西作为非成员(免费)函数接受double

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

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

Also the way you invoke them is different. 调用它们的方式也不同。 First of all, with member functions, you need an object to invoke them on (its address will eventually be bound to the this pointer in the function call). 首先,使用成员函数,您需要一个对象来调用它们(它的地址最终将绑定到函数调用中的this指针)。 Second, you need to use the .* operator (or the ->* operator if you are performing the call through a pointer): 其次,如果通过指针执行调用,则需要使用.*运算符(或->*运算符):

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

Consistently, you will have to change your definition of function print() : 一致地,您将不得不更改函数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);
}

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 typedef s and a macro. 成员函数的指针最好用typedef和宏来处理。

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? 来源: [33.6]使用指向成员函数的指针调用成员函数时,如何避免语法错误? , C++ FAQ . C ++ FAQ

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 typedef called CAGetter , this will make variable declaration much simpler: 在你的class ,声明一个名为CAGettertypedef ,这将使变量声明更加简单:

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()方法,成员变量或继承和多态来解决。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM