Передача элемента функции указателя на объект-член в С++
У меня проблема с использованием указателя на функцию в С++. Вот мой пример:
#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 С++ запрещает принимать адрес связанной функции-члена для формирования указатель на функцию-член. Сказать '& Амп; Foo:: привет
не может преобразовать 'void (foo::)()' в 'void()()' при назначении
Итак, я попробовал это следующим образом:
class bar
{
public:
void (*foo::funcP)();
};
Но теперь компилятор добавляет еще одно:
'foo' не был объявлен
Есть ли способ заставить его работать?
Заранее благодарим за предложения
Ответы
Ответ 1
Принимая все предложения вместе, ваше окончательное решение будет выглядеть следующим образом:
#include <iostream>
using std::cout;
usind std::endl;
class foo; // tell the compiler there 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;
}
С++ FAQ Lite содержит некоторые рекомендации по упрощению синтаксиса.
Принимая идею Криса и работая с ней, вы можете получить что-то вроде этого:
#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;
}
Ответ 2
Как говорится в ошибке, методы относятся к классу, а не к отдельным экземплярам. По этой причине указатели на бесплатные функции и указатели на нестатические методы - это совершенно разные вещи. Вам также понадобится экземпляр для вызова метода.
//declaring and taking the address of a foo 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.Bind и Boost.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;
}
Ответ 3
Чтобы сделать ваш второй вариант работы, объявите foo, чтобы компилятор знал, что это класс.
Также обратите внимание, что ваш синтаксис указателя функции неверен. *
появляется непосредственно перед именем переменной:
class foo;
class bar
{
public:
void (foo::*funcP)();
};
Ответ 4
форвардная декларация foo перед строкой:
class foo;