Reputation: 159
I am writing simple experiment code to test out assigning member function of one class to the function pointer who is a member of another class. My sample code did not compile. The compiler gave an error saying: '&': illegal operation on bound member function expression.
I see some people do (&ClassB::printFun) when passing a pointer to a member function. It didn't work for me because printFun is not a static member function. I have also seen people using std::bind. But std library is not a option for me since I will be using this to write kernel mode code. I have being searching for the right way to do this for a while, can someone help me out? Thanks!
using namespace std;
class ClassA
{
public:
ClassA(void(*callBack)(int));
void (*funPtr)(int);
};
ClassA::ClassA(void(*callBack)(int))
{
funPtr = callBack;
}
class ClassB
{
public:
void printFun(int a)
{
cout << a << endl;
}
};
int main()
{
ClassB classB;
ClassA classA(&classB->printFun);
classA.funPtr(5);
return 0;
}
Upvotes: 2
Views: 3490
Reputation: 332
I've not compiled this so not sure how accurate it is, but I'd be working towards something like this in a modern compiler (pre C++17 still):
#include <functional>
class A {
public:
A(std::function<void(int)> func)
: func_( func )
{}
std::function<void(int)> func_;
}
class B {
public:
void printer(int val) { /* do something */ }
}
int main()
{
B b{};
A a([&](int val) { b.printer( val ); });
a.func_(1);
return 0;
}
Upvotes: 5
Reputation: 210909
Pointers to function and pointers to member functions are different things. You need an object to call a member function.
A pointer to a meber function can be declared like this:
void (ClassB::*ptrPtrintFunc)(int) = &ClassB::printFun;
And you can call it like this:
ClassB classB;
(classB.*ptrPtrintFunc)(1);
or this:
ClassB *ptrClassB = &classB;
(ptrClassB->*ptrPtrintFunc)(2);
What you can do ist to use std::function
instead a of the old school function pointer.
You can pass a lambda function to the std::function
, in which you call the method of the class:
#include <iostream>
#include <functional> // std::function
struct ClassA
{
using TFunc = std::function<void( int )>; // <-- std::function<void( int )> insted of void(*)(int)
ClassA( TFunc func) : funPtr( func ) {}
TFunc funPtr;
};
struct ClassB
{
void printFun( int a ) { std::cout << a << std::endl; }
};
int main()
{
ClassB classB;
ClassA classA( [&classB]( int a ) { classB.printFun(a); } ); // <-- lambda function
classA.funPtr(5);
return 0;
}
Instead of the lambda function, you can also use std::bind
with a std::placholder
for the parameter:
ClassB classB;
ClassA classA( std::bind( &ClassB::printFun, &classB, std::placeholders::_1 ) );
classA.funPtr(5);
Of course you can also pass a simple function to std::function
void printFunc( int a ) { std::cout << a << std::endl; }
ClassA classA( printFunc );
Thanks for the information. I am using std library to print in the experimenting code. But the actual code I am writing is in kernel mode, so I will not have access to std library. I wonder if there is another way to do this.
If you don't want to use STL anyway you can think about a solution with an abstract base class. You need a base class with an abstract callback method and you need 2 derived classes which overrides the abstract callback method. The implementations of the callback methods delegate the callback either to a function or to class method.
Abstract class with the abstract methode CallBack
:
struct CCallBack
{
virtual void CallBack( int ) = 0;
};
Implementation for a function pointer. The overridden method CallBack
delegates the callback to a function pointer:
struct CCallBackFunc : public CCallBack
{
typedef void(*TFuncPtr)(int);
TFuncPtr _funcPtr;
CCallBackFunc( TFuncPtr funcPtr ) : _funcPtr( funcPtr ) {}
virtual void CallBack( int a ) override { (*_funcPtr)( a ); }
};
Implementation for a method function pointer. The overridden method CallBack
delegates the callback to an
object and a method function pointer:
template < class T >
struct CCallBackMethod : public CCallBack
{
typedef void(T::*TMethodPtr)(int);
T &_obj;
TMethodPtr _methodPtr;
CCallBackMethod( T &obj, TMethodPtr methodePtr ) : _obj( obj ), _methodPtr( methodePtr ) {}
virtual void CallBack( int a ) override { (_obj.*_methodPtr)( a ); }
};
Example for the use of both cases:
struct ClassA
{
ClassA( CCallBack *cb ) : _cb( cb ) {}
virtual ~ClassA() { delete _cb; }
CCallBack *_cb;
};
struct ClassB { void printFun( int a ) { std::cout << a << std::endl; } };
void printFun( int a ) { std::cout << a << std::endl; }
int main()
{
ClassB classB;
ClassA classA0( new CCallBackFunc( &printFun ) );
ClassA classA1( new CCallBackMethod<ClassB>( classB, &ClassB::printFun ) );
classA0._cb->CallBack( 6 );
classA1._cb->CallBack( 7 );
return 0;
}
Upvotes: 7