在C++中将成员函数指针传递给成员对象

27

我在使用C++中的函数指针时遇到了问题。以下是我的示例:

#include <iostream>

using namespace std;

class bar
{
public:
    void (*funcP)();
};

class foo
{
public:
    bar myBar;
    void hello(){cout << "hello" << endl;};
};

void byebye()
{
    cout << "bye" << endl;
}


int main()
{
    foo testFoo;

    testFoo.myBar.funcP = &byebye;         //OK
    testFoo.myBar.funcP = &testFoo.hello;  //ERROR
    return 0;
}

编译器在 testFoo.myBar.funcP = &testFoo.hello; 报错:

ISO C++ 禁止使用绑定的成员函数的地址来形成成员函数指针。请使用 '&foo::hello'

在赋值中无法将 'void (foo::)()' 转换为 'void ()()'

我尝试了这样写:

class bar
{
public:
    void (*foo::funcP)();
};

但现在编译器又添加了一个错误信息:

'foo'未被声明

有办法解决这个问题吗?

提前感谢您的建议。

4个回答

16

综合各位的建议,您的最终解决方案将如下:

#include <iostream> 
using std::cout;
usind std::endl;

class foo; // tell the compiler there's a foo out there.

class bar 
{ 
public: 
    // If you want to store a pointer to each type of function you'll
    // need two different pointers here:
    void (*freeFunctionPointer)();
    void (foo::*memberFunctionPointer)();
}; 

class foo 
{ 
public: 
    bar myBar; 
    void hello(){ cout << "hello" << endl; }
}; 

void byebye() 
{ 
    cout << "bye" << endl; 
} 


int main() 
{ 
    foo testFoo; 

    testFoo.myBar.freeFunctionPointer = &byebye;
    testFoo.myBar.memberFunctionPointer = &foo::hello;

    ((testFoo).*(testFoo.myBar.memberFunctionPointer))(); // calls foo::hello()
    testFoo.myBar.freeFunctionPointer();   // calls byebye()
    return 0; 
} 

C++ FAQ Lite中提供了一些简化语法的指南。

借鉴Chris的想法,你可以得到如下代码:

#include <iostream>
using std::cout; using std::endl;

class foo;
typedef void (*FreeFn)();
typedef void (foo::*MemberFn)();

class bar
{
public:
  bar() : freeFn(NULL), memberFn(NULL) {}
  void operator()(foo* other)
  {
    if (freeFn != NULL) { freeFn(); }
    else if (memberFn != NULL) { ((other)->*(memberFn))(); }
    else { cout << "No function attached!" << endl; }
  }

  void setFreeFn(FreeFn value) { freeFn = value; memberFn = NULL; }
  void setMemberFn(MemberFn value) { memberFn = value; freeFn = NULL; }
private:
  FreeFn freeFn;
  MemberFn memberFn;
};

class foo
{
public:
  bar myBar;
  void hello() { cout << "foo::hello()" << endl; }
  void operator()() { myBar(this); }
};

void bye() { cout << "bye()" << endl; }

int main()
{
  foo testFoo;

  testFoo();

  testFoo.myBar.setMemberFn(&foo::hello);
  testFoo();

  testFoo.myBar.setFreeFn(&bye);
  testFoo();

  return 0;
}

不错,但是如何运行memberFunctionPointer指向的函数?testFoo.myBar.*memberFunctionPointer()会导致错误。 - Moomin
@moomin:这次我添加了正确调用函数的示例。 - Bill
为了完整性,您可能希望向 bar 添加一个默认构造函数,将两个指针都设置为 0。您可以设置类,使其始终仅设置一个成员(即将一个成员设置为 0),然后添加一个 operator() 函数来调用设置的成员。虽然最终会比这更复杂。 - Chris Lutz

12

正如错误提示所说,方法属于类,而不是单独的实例。因此,指向自由函数的指针和指向非静态方法的指针是完全不同的东西。您还需要一个实例才能调用该方法。

//declaring and taking the address of a foo's method 
void (foo::*method)() = &foo::hello; //as the compiler nicely suggests

//calling a function through pointer
free_func();

//calling a method through pointer
foo instance;
(instance.*method)();

你可以使用类似于Boost.BindBoost.Function(我认为也在std::tr1中)的库来抽象出差异,并将实例绑定到方法:

#include <iostream>
#include <boost/bind.hpp>
#include <boost/function.hpp>

using namespace std;

class foo
{
public:
    void hello(){cout << "hello" << endl;};
};

void byebye()
{
    cout << "bye" << endl;
}


int main()
{
    foo testFoo;

    boost::function<void()> helloFunc(boost::bind(&foo::hello, testFoo));
    boost::function<void()> byeFunc(byebye);

    helloFunc();
    byeFunc();
    return 0;
}

请问如何运行testFoo.myBar中的"hello()"呢? 我已经执行了'testFoo.myBar.funcP = &foo::hello;',但是在编译期间执行'(testFoo.myBar.*funcP)();'时返回了'funcP未声明...' - Moomin

1
为了让你的第二个选项起作用,需要声明foo,这样编译器就知道它是一个类。
另外请注意,你的函数指针语法是不正确的。星号*应该放在变量名之前:
class foo;

class bar
{
public:
    void (foo::*funcP)();
};

0
将foo的声明放在bar前面:
class foo;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接