将成员函数作为参数传递/c++

Posted

技术标签:

【中文标题】将成员函数作为参数传递/c++【英文标题】:passing member functions as parameters / 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 会给你提供比你想知道的更多关于传递成员函数的信息。 【参考方案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);

;

【讨论】:

以上是关于将成员函数作为参数传递/c++的主要内容,如果未能解决你的问题,请参考以下文章

E0312, C2664 尝试将矢量对象作为函数参数传递时出错

将成员函数作为委托参数传递

如何将成员函数作为参数传递?

C++11多线程第三篇:线程传参详解,detach()大坑,成员函数做线程参数

C++11多线程第三篇:线程传参详解,detach()大坑,成员函数做线程参数

如何将成员函数作为与 Windows 上的蓝牙相关的参数回调函数传递?