Passing a function pointer to a function - c++

What should I do if I want to pass a non-static member function of any class as a click function of the button ? Is it possible ? If so what do I need to do ? For example in which ever class (EntityToolGUI over here) the button is initiatlized, I want to set its click action to a non-static member function (a non-static member function of class EntityToolGUI ) of that class.
GUIButton.h
typedef void (*ptr2clickFunc)(void);
class GUIButton : public GUIObject {
private : void (*clickFunc)(void);
public : void setClickFunction(ptr2clickFunc clickFunc);
};
GUIButton.cpp
void GUIButton::setClickFunction(ptr2clickFunc clickFunc)
{
this->clickFunc = clickFunc;
}
EntityToolGUI.h
class EntityToolGUI {
public : EntityToolGUI();
protected : void addAnimation();
}
EntityToolGUI.cpp
void EntityToolGUI::addAnimation()
{
cout<<"add animation"<<endl;
}
EntityToolGUI::EntityToolGUI()
{
....
btnAddAnimation->setClickFunction(&EntityToolGUI::addAnimation);
}
I am getting an error no matching function call to GUIButton::setClickFunction(void (EntityToolGUI::*)())
candidate is void GUIButton::setClickFunction(void (*)())
How do I solve this ?

Most (decent) C code that passes function pointers around use an extra void* argument for passing user context to the function. This is not so common in C++ (as better techniques than function pointers exist), but if you're stuck using function pointers for some reason then it may be appropriate.
typedef void (*ptr2clickFunc)(void*);
class GUIButton : public GUIObject {
private : ptr2clickFunc clickFunc;
private : void * userdata;
public : void setClickFunction(ptr2clickFunc clickFunc, void* userdata);
};
class Foo
{
static void do_foo( void * userdata )
{
Foo* thisptr = static_cast<Foo*>(userdata);
thisptr->foo();
}
void foo() { ... }
};
int main()
{
Foo foo;
GUIButton button;
button.setClickFunction( &Foo::do_foo, &foo );
button.click();
}
EDIT As noted by Bartek, if you're doing this a lot you can extract the static function into a template - it looks a bit like this (untested and probably with minor errrors).
// GUIButton is as before
// Note no static function here
class Foo { void foo(); }
template<typename T, void(T::*FN)() >
void Call( void * data)
{
static_cast<T*>(data)->*FN();
}
int main()
{
Foo f;
GUIButton button;
button.setClickFunction( &Call<Foo,&Foo::foo>, &f );
button.click();
}

If you want to pass obj fun ptr you can use boost::bind and boost::function
http://www.boost.org/doc/libs/1_50_0/libs/bind/bind.html

You cannot pass a pointer to non-static member function as a pointer to a "regular" non-member function. You should either make addAnimation static, or make ptr2clickFunc typedef a pointer to member function.
Note that invoking a pointer to member function is different from invoking a function pointer, because you must supply an instance on which the member pointer is to be invoked.

addAnimation needs to be static function. When the call back function is set the way you are doing it now, the object of class EntityTollGUI is not registered along with the function.

Try this one (C++11):
#include <stdio.h>
#include <stdlib.h>
#include <functional>
class Raiser
{
public:
std::function<void(int)> ev1, ev2;
void RaiseEv1()
{
if (!ev1._Empty())
ev1(44);
}
void RaiseEv2()
{
if (!ev2._Empty())
ev2(66);
}
};
class Handler
{
private:
int id;
std::function<void(int)> h;
public:
Handler(int newId)
{
id = newId;
h = [this](int i)
{
printf("Handler with id = %d captured event!\n", this->GetId());
};
}
void Hook1(Raiser & raiser)
{
raiser.ev1 = h;
}
void Hook2(Raiser & raiser)
{
raiser.ev2 = h;
}
int GetId()
{
return id;
}
};
int main(int argc, char * argv[])
{
Raiser raiser;
Handler handler1(1), handler2(2);
handler1.Hook1(raiser);
handler2.Hook2(raiser);
raiser.RaiseEv1();
raiser.RaiseEv2();
getchar();
}
AFAIK, this is the most you can get with events in C++ without using language extensions.

Related

How to change a Callback signature that also accepts class methods and free functions?

I have a Callback which looks like this:
typedef void(*Callback)(EventInfo event_info);
This can be used with free functions, but when I try to use class methods it fails with the error :
Error C2276 '&': illegal operation on bound member function expression
How should I go about this and make it so that it also accepts a class method just like a free function. That is I could simply do :
struct MyClass
{
void some_methods(EventInfo info)
{
sth;
}
}
void some_functions(EventInfo info)
{
sth;
}
int main()
{
MyClass obj;
myobj.AddOnSthChanged(obj.somemethods);
myobj.AddOnSthChanged(some_functions);
...
Pointers on function are limited to .. pointers on function.
To allow any callable, you have to use template or type erasure as std::function:
using Callback = std::function<void(EventInfo)>;
struct MyClass
{
Callback callback;
};
struct A
{
void foo(EventInfo) {}
};
void bar(EventInfo) {}
int main()
{
EventInfo event;
MyClass c1{bar};
c1.callback(event); // bar(event);
A a;
MyClass c2{ [&a](EventInfo event){ a.foo(event); }};
c1.callback(event); // a.foo(event);
}

How to pass function pointer (callback) and call it without knowing it's type?

I have a function pointer as a member to a pure virtual base class. I'd like to pass this pointer to a library which does not know about either of these classes, MyBase or MyClass, and then call the function pointer as a callback into MyClass. I'm writing the lib as well. I want the shared library to call a callback in MyClass.
My question is, how does one pass a function pointer as an argument to a function and have it called without knowing anything about the class itself.
I was considering a pointer to a function pointer, but wasn't sure how to cast properly.
class MyBase {
public:
virtual void callback() = 0;
void (MyBase::*callback_ptr)();
};
class MyClass : public MyBase {
public:
MyClass();
void callback() { cout << "callback called" << endl; };
};
main.cpp
{
MyClass my_class;
my_class->callback_ptr = &MyBase::callback;
lib->set_callback(my_class->callback_ptr);
}
lib.cpp
class MyLib {
public:
// how to declare the member function pointer here?
void** callback_ptr;
// how to write sig here?
set_callback(ptr) { callback_ptr = ptr }
running() {
// how to call the callback here w/o knowing it's type?
}
}
#include <iostream>
#include <functional>
using namespace std;
class Foo {
public:
void myFunction() {
cout << "Foo::myFunction()\n";
}
};
void myAPICall(std::function<void()> arg) {
arg();
}
int main(int, char**) {
Foo foo;
// Using a lambda
myAPICall( [&]() { foo.myFunction(); } );
// Using bind
myAPICall( std::bind(&Foo::myFunction, foo) );
return 0;
}
Yields:
$ g++ -std=c++11 f.cpp -o f && f
Foo::myFunction()
Foo::myFunction()
This assumes that you control the API you're calling, and it uses std::function like my code does. If it accepts a C-style function pointer rather than std::function, then you're going to have to play much different games.
To get a function pointer when you don't know the exact type of function that will be called, use std::function from the <functional> header.
class MyLib {
public:
// how to declare the member function pointer here?
std::function<void()> callback_ptr;
// how to write sig here?
void set_callback(std::function<void()> ptr) { callback_ptr = ptr; }
void running() {
callback_ptr();
}
};
To use a member function as a std::function, use std::bind:
int main()
{
MyClass my_class;
MyLib my_lib;
my_lib.set_callback(std::bind(&MyClass::callback, &my_class));
my_lib.running(); // calls my_class.callback()
}

Passing non-static member function as argument to a member function in a different class

UPDATE I realize this question's lacking a proper MCVE, it will take me some time to come up with one. I will update it when I have time to come back to this, sorry. I appreciate the answers thus far.
Following this answer regarding static functions:
Declaration (in MyClass)
void MyClass::func ( void (MyOtherClass::*f)(int) ); //Use of undeclared identifier 'MyOtherClass'
Example of function being passed to func:
void MyOtherClass::print ( int x ) {
printf("%d\n", x);
}
Function call (in MyOtherClass)
void MyOtherClass::loop(){
func(&MyOtherClass::print);
}
How can one pass a member function as a parameter of a member function of another class?
According to the ISO, the answer is "don't". Unlike normal functions, a non-static member function is meaningless without an instance of the class. As a workaround, you can have your calling function take a std::function and pass it a lambda.
Example:
void calling_func(std::function<void()> f);
struct foo
{
void func();
void call()
{
calling_func([this]{
func();
});
}
};
can't you just use std::function and std::bind to that?
class MyOtherClass
{
public:
MyOtherClass() {}
void print(int x)
{
printf("%d\n", x);
}
};
class MyClass
{
private:
std::function<void()> CallbackFunc;
public:
MyClass() {};
void AssignFunction(std::function<void(int)> callback, int val)
{
CallbackFunc = std::bind(callback, val); //bind it again so that callback function gets the integer.
}
void DoCallback()
{
CallbackFunc(); //we can then just call the callback .this will, call myOtherClass::print(4)
}
};
int main()
{
MyClass myObject;
MyOtherClass myOtherObject;
int printval = 4;
//assign the myObject.callbackfunc with the myOtherClass::print()
myObject.AssignFunction(std::bind(&MyOtherClass::print, myOtherObject,std::placeholders::_1), 4);
//calling the doCallback. which calls the assigned function.
myObject.DoCallback();
return 0;
}

function pointer to a class member

I am trying to do some like this:
class A {
void *(*func)(void *);
A(void *(*function)(void *)){
func = function;
}
}
class B {
void *real_func(void *);
A ptr;
B()
:ptr(&real_func)
{
...
}
}
But I get this error:
error: ISO C++ forbids taking the address of an unqualified or
parenthesized non-static member function to form a pointer to member
function.
Someone knows how to initialize the function pointer to a function member in the same class???
Thanks!
Carlos
Since real_func is not a static member function, its type cannot be void *(*)(). Instead, it is void *(B::*)() so you need to declare func accordingly:
void *(B::*func)();
// call it like this
pointer_to_b->*func();
If you are careful, you can also use pointer to A as the base class, but you must make sure that the pointer to A points to an instance of B:
void *(A::*func)();
At this point, however, you are mostly just replicating the functionality of virtual member functions. So I would recommend you use that instead:
class A {
virtual void *func() = 0;
};
class B {
void *func() {
// ...
}
};
You could create B like this:
struct B {
static void *real_func(void *);
A ptr;
B()
:ptr(&real_func)
{
...
}
};
A static member function acts like a regular function, so you can create a function pointer for it.
If you don't need a regular function pointer, then you can use std::function:
#include <functional>
struct A {
std::function<void *(void*)> func;
A(std::function<void *(void*)> function)
: func(function)
{
}
};
struct B {
void *real_func(void *);
A ptr;
B()
: ptr(std::bind(&B::real_func,this,std::placeholders::_1))
{
}
};

Converting method signatures

typedef void (__thiscall* LPVOIDPROC) (void);
class ClassA
{
LPVOIDPROC m_pProc;
void SetProc(LPVOIDPROC pProc) { m_pProc = pProc; }
void OnSomeEvent() { m_pProc(); }
}
class ClassB
{
ClassA* pCA;
void Proc() { /* ... */ }
void Init()
{
// Assume pCA != NULL
pCA->Set((LPVOIDPROC)&ClassB::Proc); // error C2440
}
}
How to get rid of this error C2440: 'type cast' : cannot convert from 'void (__thiscall ClassB::* )(void)' to 'LPVOIDPROC' ? I don't want to limit LPVOIDPROC signature to ClassB only. This should be any class and referenced proc should not be static.
Workaround:
typedef void (* CLASSPROC) (void *);
template<class T, void (T::*proc)()>
void class_proc(void * ptr)
{
(static_cast<T*>(ptr)->*proc)();
}
class ClassA
{
CLASSPROC m_pProc;
void * m_pInstance;
public:
void SetProc(void *pInstance, CLASSPROC pProc) {
m_pInstance = pInstance;
m_pProc = pProc;
}
void OnSomeEvent() { m_pProc(m_pInstance); }
};
class ClassB
{
ClassA* pCA;
void Proc() { /* ... */ }
void Init()
{
// Assume pCA != NULL
pCA->SetProc(this, class_proc<ClassB, &ClassB::Proc>);
}
};
I refer you to this link. Your type LPVOIDPROC is a pointer-to-function, which is not the same thing as a pointer-to-member-function. When you try to cast ClassB::Proc, you are trying to convert a pointer-to-member-function, an invalid operation.
You should take a look at boost::function, that offers exactly what you are looking for. Or you could use functors to encapsulate your functions if you don't want to resort to boost. Example:
struct VoidProcFunctor {
virtual void call() = 0;
};
class ClassB;
struct BProcFunctor : VoidProcFunctor {
BProcFunctor(ClassB* b) : b_(b) {}
void call();
private:
ClassB* b_;
}
class ClassA
{
public:
VoidProcFunctor* m_pProc;
void SetProc(VoidProcFunctor* pProc) { m_pProc = pProc; }
void OnSomeEvent() { m_pProc->call(); }
};
class ClassB
{
ClassA* pCA;
void Proc() { /* ... */ }
void Init()
{
// Assume pCA != NULL
// warning! this is not the best design possible
BProcFunctor* bproc = new BProcFunctor(this);
pCA->SetProc(bproc);
}
};
void BProcFunctor::call() { b_->proc() }
Non-static methods require a 'this' pointer, without a 'this' pointer you cannot call it, and so it makes no sense to cast it to a C function pointer.
Consider making a simple class (let's call it X) that has
a data member that refers to a ClassB instance
a () operator (although I prefer methods with clear names) calling ClassB::Proc using the ClassB instance as this-pointer.
Instead of passing a function pointer to class A, make an instance of X (with its datamember to ClassB filled in) and pass this to class A.
Instead of calling a function pointer class A should call x().
Class X could even be written using templates, so if you have this situation for more than one class you must only write it once.
I think that in C# it can be done cleaner using delegates but I leave that to the C# and .Net specialists.
Never cast function pointers. You can end up with stack corruption. Don't do it.
Don't pass pointers to non-static member functions. They use a different calling convention and are not compatible.
In your case, making "Proc()" static might solve the problem.
You need your Proc method to be a static method.