3

假设我有一个类和一个函数

class A
{
    int a;
    int b;
    int mul()
    {
        return a+b;
    }
};
...

void func(int af, int bf, int (*fc)())
{
    ...
}

在主函数中,该函数应该使用A类的方法

int main
{
    A as;
    ...
    func(as.a, as.b, as.mul);
}

但是,我不能那样做,编译器一直告诉我我正在通过

(int&, int&, 'unresolved overloaded function type') 

成为候选函数

(int, int, void(*)()).

为什么会这样,以及如何将类的方法传递给另一个函数?

哦,我想我应该把问题说清楚一点。func(...)实际上是我正在研究的算法中的一个函数。并且class A是一个将使用该算法进行模拟的模型。所以我认为我不会在函数 B 中专门使用 A 的实例,而只是将 A 的方法和组件传入并使用它们。


更新:有些人提到在 A 类中使用静态方法。但是,这仍然是部分解决方案。使用静态方法mul()将迫使我声称 a 和 b 都是静态的。如果我必须使用 A 的多个实例,并且在我的主函数中的每个实例中使用不同的方法 a、b,那么使用静态变量将完全失败。

那么,关于如何在不使用静态变量/方法的情况下解决此问题还有其他建议吗?我记得在诸如 python 之类的脚本语言中,传递任何类型的方法基本上都不是问题。为什么我不能在 C++ 中做类似的事情?或者 C++ 中是否有解决方法可以帮助我做到这一点?

4

5 回答 5

5

首先,mulis 的成员函数A因此您不能像调用全局函数或static成员函数一样调用它:它需要一个调用该函数的对象:

A::mul(); // ERROR!
A a;
a.mul(); // OK

这就是说,您可以更改 的定义func以接受指向成员函数的指针:

void func(int af, int bf, void (A::*fc)())
//                        ^^^^^^^^^^^^^^^

但是,仅此更改不会使您取得太大进展,因为您仍然没有传递A应该在其上调用成员函数的具体实例。换句话说,这将是非法的:

fc(); // ERROR!

为了克服这个限制,你可以传递一个引用或一个指向Atogether to实例的指针func,并按如下方式调用它:

void func(A* pA, int af, int bf, void (A::*fc)())
{
    ...
    (pA->*func)();
}

但是,如果func()将调用成员函数的对象作为参数传入,则不清楚afand的目的是什么bf

可能,如果您的mul()成员函数不需要处理 的任何具体实例A,并且仍然希望使其成为 的成员A,则可以将其声明为static

class A
{
    int a;
    int b;
    static void mul();
//  ^^^^^^
};

这将使您最初调用func()编译。但是,在这种情况下,不清楚这是否有意义,因为不mul()接受参数这一事实表明它应该在调用它的对象的ab成员上工作。

于 2013-03-28T17:50:12.547 回答
1

您要做的是将成员函数指针 ( A::mul) 与实例 ( a) 本身一起传递。没有任何额外的代码,这并不容易。

成员函数指针不绑定到实例(它们只表示函数本身,而不是要调用的实例)。它们的类型与类名一起描述。A带有您的签名的成员函数指针的类型func如下所示:

void (A::*)()     // The type only, anonymous
void (A::*fc)()   // An actual function pointer with the name `fc`

要调用这样的函数,您必须使用以下语法,如您所见,必须涉及调用函数的实例:

(a->*fc)();       // If a is of type A*
(a.*fc)();        // If a is of type A or A&

把事情放在一起,你基本上有两个选择。

  1. 除了成员函数指针之外,还要传递实例(作为指针、引用、const 或可修改)。然后,调用该实例上的成员函数指针。

    您的函数签名和实现将如下所示:

    void func(int af, int bf, void (A::*fc)(), A *a) {
        // When you want to call the function fc on a:
        (a->*fc)();
    }
    

    要调用func,请使用如下代码:

    func(as.a, as.b, &A::mul, a);
    
  2. 将成员函数指针与实例一起转换为可以按原样调用的函子。这最好与 withstd::mem_fn一起完成std::bind1st

    您的函数签名和实现将如下所示:

    void func(int af, int bf, std::function<void()> fc) {
        // When you want to call the function fc:
        fc();
    }
    

    要调用func,请使用如下代码:

    func(as.a, as.b, std::bind1st(std::mem_fn(&A::mul), a));
    
于 2013-03-28T17:49:52.400 回答
1

是否mul注定是一个非静态成员,需要一个类型的对象A来调用它?在这种情况下,您需要传递一个指向成员的指针:

void func(int af, int bf, void (A::*fc)())
{ //                            ^^^  
    A a = whatever();
    (a.*fc)();
}

如果它打算在没有对象的情况下被调用,那么它需要是static.

于 2013-03-28T17:52:06.623 回答
1

如果您真的想将int (*fc)(int,int)void在另一个示例中给出的 return 和空参数列表)视为常规函数指针(我的意思不是指向类成员函数的函数指针),您可以执行以下操作来使用函数A并将其传递给func. 关键是声明mul为静态成员函数。我假设非常简单的操作,比如乘法。

#include <iostream>
class A
{
public: //necessary otherwise not accessible in main
   int a;
   int b;
   A(int p1, int p2):a(p1),b(p2){} //assume you need to somehow pass a,b into mul
   static int mul(int p1, int p2)  {return p1*p2;};  //mul should be static
};

void func(int af, int bf, int (*fc)(int,int))  
//using void still work but you need to change declaration of mul in A
{
  int res = fc(af,bf);  
  cout << res <<endl;
}

int main()
{
  A as(2,4);
  func(as.a, as.b, &A::mul); //call A::mul, use as regular function pointer, output 8
  func(10,10, &A::mul); //will output 100
  return 0;
}

这样,您就可以使用 A 的静态成员函数,该函数可以由常规函数指针指向。a它与b课堂无关。

于 2013-03-28T18:18:41.987 回答
1

正如 leemes 所说,您也可以这样做,std::function这也是我的建议,但请查看您的编译器支持什么,如果支持,您可以使用一次调用std::bind并让它工作。下面的示例适用于 Visual Studio 2012(并且应该适用于启用了 C++11 标志的较新版本的 GCC,并且可能适用于也可能不适用于 VS 2010)

void func(int af, int bf, std::function<void()> fc)
{
    fc();
}

致电:

func(as.a, as.b, std::bind(&as::mul, &A));

如果它检测到成员函数,则较新的版本会为您std::bind完成部分工作。std::mem_fcn请参阅此处链接的文档:

标准::函数

标准::绑定

于 2013-03-28T18:37:28.703 回答