【问题标题】:How to pass method of a class into another function in C++?如何将一个类的方法传递给 C++ 中的另一个函数?
【发布时间】:2013-03-19 07:00:00
【问题描述】:

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

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

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

在main函数中,该函数应该使用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 的多个实例,并且我的 main 函数中的每个实例中的方法 a、b 不同,那么使用静态变量就会失败。

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

【问题讨论】:

  • 你想做什么,更具体地说?
  • 您可以使用 boost::bind 做您需要的事情,或者如果 C++11 可用,您可以使用 lambda。
  • 正如 Song Wang 和 Andy 所建议的,问题出在函数指针上。如果要将类的函数方法传递给函数,则它必须是静态的,以便有一个定义明确的指针可以传递。
  • @AndyProwl,对不起,我只是想避免过多的线程,以便减少冗余信息。我又接受了。希望不会造成任何损害。哦,顺便问一下,你知道除了使用静态方法之外的另一种方法来实现类似的目标吗?谢谢。

标签: c++ class function methods


【解决方案1】:

首先,mulA成员函数,所以不能像全局函数或static 成员函数一样调用它:它需要调用函数的对象:

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

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

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

然而,这个改变单独不会让你进步太多,因为你仍然没有传递A的具体实例,在该实例上应该调用成员函数。换句话说,这将是非法的:

fc(); // ERROR!

要克服这个限制,您可以将引用或指向A 实例的指针一起传递给func,并按如下方式调用它:

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

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

可能,如果您的mul() 成员函数不需要在A 的任何具体实例上工作,但您仍想使其成为A 的成员,您可以将其声明为static

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

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

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      【解决方案3】:

      您要做的是将成员函数指针 (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. 将成员函数指针与实例一起转换为可以按原样调用的函子。最好将std::mem_fnstd::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));
        

      【讨论】:

        【解决方案4】:

        如果您真的想将int (*fc)(int,int)(另一个示例中给出的void返回和空参数列表)视为常规函数指针(我的意思不是指向类成员函数的函数指针),您可以执行以下操作来使用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 的静态成员函数,该函数可以由常规函数指针指向。它与课堂内的ab 无关。

        【讨论】:

          【解决方案5】:

          正如 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 部分。请参阅此处链接的文档:

          std::function

          std::bind

          【讨论】:

          • 谢谢,我不知道 std::bind 的东西,但静态函数指针 leemes 建议确实有效。我会检查你给我的 std::bind 页面。谢谢~
          猜你喜欢
          • 2021-12-18
          • 2016-12-21
          • 1970-01-01
          • 2015-09-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多