这个指向非静态成员函数代码的指针不起作用的原因是什么?

What is the reason that this pointer to nonstatic member functions code doesn't work?

这就是我想要做的:

class A {
public:
    void(*fPtr)();
};

class B {
    int ib = 2;
public:
    void memf() {
        printf("ib = %i\n", ib);
    }
};

class C {
    int ic = 6;
public:
    void memf() {
        printf("ic = %i\n", ic);
    }
};

int main()
{
    B b;
    C c;
    A a1;
    A a2;
    a1.fPtr = b.memf;
    a2.fPtr = c.memf;
}

基本上是一个具有函数指针的 class。 该函数指针可以指向普通函数或成员函数。

我在 Visual Studio 中得到的错误是:

Error   C2440   '=': cannot convert from 'void (__thiscall B::* )(void)' to 'void (__cdecl *)(void)'
Error   C2440   '=': cannot convert from 'void (__thiscall C::* )(void)' to 'void (__cdecl *)(void)'    
Error   C3867   'B::memf': non-standard syntax; use '&' to create a pointer to member
Error   C3867   'C::memf': non-standard syntax; use '&' to create a pointer to member

我知道这看起来像是重复的,也许是。我没有使用推荐的解决方案,例如使用 <functional>

谁能告诉我如何正确地做,这样我才能明白我做错了什么? 我也想知道为什么标准方式不行。

换句话说:更正我的代码;) 非常感谢。

了解为什么这会导致问题的最简单方法是询问 - 如果您确实调用了函数指针指向的函数,接收者对象是什么?例如,假设您指向 B::memf,然后通过 fptr 调用它。该函数需要相对于 B 对象进行操作,以便它可以读取该 B 对象的 ib 字段的值。但是我们无法弄清楚要使用什么 B 对象 - 糟糕的时候!

(非静态)成员函数不同于自由函数的原因是它们有一个表示接收者对象的隐式参数,因此在调用该函数时需要某种方式来指定该对象是什么。

该站点上的其他答案应该能够提供一些有关解决此问题的一些可能策略的信息,但希望这首先能阐明问题所在。

这是您问题的可能解决方案:不过,我做了一些细微的改动。

  • 1st - I changed Class A to a Class Template.
  • 2nd - I added a pointer to type <T> as a class member.
  • 3rd - I added an operator()() to A<T> to invoke the function call.
  • 4th - I changed the name of your function pointer and the name of the functions of the other classes just to be consistent.
  • 5th - Instead of using printf(), I used std::cout.

修改后的代码如下所示:阅读评论以了解其工作原理。

template<class T>
class A {
private:
    // Need to save a pointer to the class to have a realitive object.
    T* ptrT{ nullptr };
public:
    // Assigns the pointer of the object to this's class's pointer member.
    // Must pass by reference otherwise you will have undefined behavior.
    explicit A( T& t ) : ptrT( &t ) {}

    // Notice the Template Arguments class resolution operator...
    void(T::*func)();

    // The added operator()() to invoke the function call.
    // This could of been any arbitrary member function; 
    // I just chose to use the operator() for demonstration.
    void operator()() {
        (ptrT->*func)();
    }
};

// In class's A & B the only changes here are 
// the names of the function and replacing printf() with cout
class B {
    int ib{ 2 };
public:
    void func() {
        std::cout << ib << '\n';
    }
};

class C {
    int ic{ 6 };
public:
    void func() {
        std::cout << ic << '\n';
    }
};

int main() {
    try {
        B b;
        C c;
        // Changes to A by using templates and passing the object      
        // above to A's explicit constructor
        A<B> a1( b );
        A<C> a2( c );

        // Notice the syntax on how to assign the function pointer.
        a1.func = &B::func;
        a2.func = &C::func;

        // using the operator() to invoke the function pointer.
        a1();
        a2();
    } catch( std::runtime_error& e ) {
        std::cerr << e.what() << std::endl;
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;    
}

-输出-

2
6