将成员函数作为参数传递/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(<unresolved overloaded function type>)’
fp.cpp:6:注意:候选人是:void b::foreach_x_do(void (*)(int))
谁能帮忙编译一下?
【问题讨论】:
一方面,您传递给foreach_x_do
的f
不是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<>
而不是函数指针:
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::bind
和std::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::function
或boost::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()大坑,成员函数做线程参数