【问题标题】:passing member functions as parameters / c++将成员函数作为参数传递/c++
【发布时间】:2011-05-19 18:20:37
【问题描述】:

我想在 C++ 中实现一个类 b,它可以通过封装该迭代器类型的成员集进行某种迭代。喜欢:

b_object.for_each_x_do(function_f);

所以 function_f 会得到 x 成员中的每个人并做任何事情。比方说:

void function_f(x_member_type x){ cout << x << endl; }

好的。所以我试图通过如下代码来实现:

class b{
    int *x;
public:
    void foreach_x_do(void (*f)(int)){
            while(*x++)  // or any kind of iteration through x
                    f(*x);
    }
};

class a{
    b b_inst;
public:
    void f(int x) {  }     
    a(){
            b_inst.foreach_x_do(f); // by mistake it was b_inst.foreach_x_do(f)(), however this wasn't the point at all. 
    }
    ~a(){}
};

int main(){} 

但是,我收到了这个错误,编译时:

fp.cpp: 在构造函数‘a::a()’:
fp.cpp:17: 错误: 没有匹配函数调用 ‘b::foreach_x_do(&lt;unresolved overloaded function type&gt;)’
fp.cpp:6:注意:候选人是:void b::foreach_x_do(void (*)(int))

谁能帮忙编译一下?

【问题讨论】:

  • 一方面,您传递给foreach_x_dof 不是void(*)(int),而是void (a::*)(int)
  • 只是一个旁注,你应该用大写来命名你的类。所以class B 而不是class b。只是为了符合常见用法。
  • This FAQ 会给你提供比你想知道的更多关于传递成员函数的信息。

标签: c++ member-function-pointers


【解决方案1】:

正如@steveo225 所述,f 在该上下文中的类型为void (a::*)(int) 而不是void (*)(int)。有两种方法可以解决这个问题——第一种是使 b::foreach_x_do 成为一个成员函数模板,它可以接受任何可调用类型:

class b {
    int* x;

public:
    b() : x() { }
    template<typename F>
    void foreach_x_do(F f) {
        while(*x++)
            f(*x);
    }
};

class a {
    b b_inst;

public:
    void f(int x) { }
    a() : b_inst() {
        b_inst.foreach_x_do(std::bind(&a::f, this, _1));
    }
};

第二个是将b::foreach_x_do 保留为非模板,并使其采用std::function&lt;&gt; 而不是函数指针:

class b {
    int* x;

public:
    b() : x() { }
    void foreach_x_do(std::function<void(int)> const& f) {
        while(*x++)
            f(*x);
    }
};

class a {
    b b_inst;

public:
    void f(int x) { }
    a() : b_inst() {
        b_inst.foreach_x_do(std::bind(&a::f, this, _1));
    }
};

在任何一种情况下,如果您的编译器太旧而无法提供std::std::tr1:: 实现,请将std::bindstd::function 替换为它们的boost:: 对应项。另请注意,如果您有 C++11 编译器,则可以使用 lambda 代替 bind

【讨论】:

    【解决方案2】:

    应该是:

    b_inst.foreach_x_do(f);
    

    您还需要将f 设为静态,而不是非静态成员方法,因为foreach_x_do 函数的原始签名用于独立函数指针,而不是指向成员函数的指针。所以,即,

    static void f(int x) {  } 
    

    【讨论】:

    • 我不知道这个解决方案是否有任何陷阱(因为该方法变成静态的)但对于我的简单任务来说它工作得很好。也许使用 bind() 的解决方案更好,但我喜欢这个,因为它更独立于编译器。
    • 主要的“陷阱”是静态函数不能直接访问类的非静态成员或方法......所以如果您需要访问非静态数据成员或方法,您必须将类对象的引用或指针作为参数传递给函数。
    【解决方案3】:

    函数for_each_x_do 需要一个函数指针,而您(试图)给它一个成员函数指针。两者不一样。前者可以直接调用,后者需要调用对象实例。我建议您改用std::functionboost::function。比如:

    void for_each_x_do(function<void (int)> f) {
      // your code here
    }
    

    然后使用 binder 构造函数对象:

    a(){
      b_inst.foreach_x_do(bind(&a::f, this, _1));     
    }
    

    【讨论】:

      【解决方案4】:

      在这一行:

       b_inst.foreach_x_do(f)();
      

      去掉第二组括号;你不需要它们。

       b_inst.foreach_x_do(f);
      

      应该可以正常工作。

      【讨论】:

        【解决方案5】:

        f() 是一个 member 函数——因此它的相关性仅限于它对应的对象。到目前为止,其中一些解决方案不起作用。

        您有两个选择,要么将函数设为静态,在这种情况下,哪个对象都没有关系,要么以某种方式传递对象。

        this helpful FAQ 中明确解释了第二种方法,专门关于传递成员函数。

        【讨论】:

          【解决方案6】:

          试试:

          class b{
          int *x;
          public:
          void foreach_x_do(void (*f)(int)){
                  while(*x++)  // or any kind of iteration through x
                          (*f)(*x);
          }
          

          };

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-09-11
            • 1970-01-01
            • 2017-12-01
            • 1970-01-01
            • 2015-04-02
            • 2019-09-27
            • 1970-01-01
            • 2018-09-18
            相关资源
            最近更新 更多