How to pass a pointer to method as a parameter? - c++

I want to pass a method as an argument to a method which takes an int and returns void:
void A::SetCallback(void (*callback)(int))
{
.....................
}
void B::test()
{
a->SetCallback(&B::Done); //
}
void B::Done(int i)
{
..........................
}
Inside test() I get this error:
Error 1 error C2664: cannot convert parameter 1 from 'void (__thiscall B::* )(int)' to 'void (__cdecl *)(int)'
I saw some example on StackOverflow how to fix this but it uses elements from C++11, to which I do not have access.
How can I fix this using C++03 ?

You cannot pass a non-static method to a function that takes a pointer to a function. Functions and methods are two completely different things. In order to invoke a non-static method you have to, obviously, have an object whose method you're invoking.
If, in your example, Done() is a static class method, then, yes, you can pass it this way, since a static class method is just another name for a function.
It is possible to have a pointer to a class method:
void A::SetCallback(void (B::*callback)(int))
{
}
void B::test()
{
a->SetCallback(&B::Done); //
}
void B::Done(int i)
{
..........................
}
But in order to invoke the class method, you need an object whose method to invoke:
B *object=give_me_a_pointer_to_b_from_somewhere();
(object->*callback)(0);

&ClassName::method_name creates the pointer and void(ClassName::*)(int, char*) is the type.
void go(void(ClassName::*parameter_name)(int, char*));
go(&ClassName::method_name);

You cannot pass a pointer to class method (which is of type void (B::*) (int) in your case) to a pointer to a free function.
What would happen if you could?
void f (void (*g) (int)) {
g(2);
}
struct A {
int x;
void foo (int c) { x += c; }
};
f(&A::foo); // Oh oh! Where will I find `x` in the call `g(2)`?
If you only want pointer to method of B, you need to change the callback type:
void A::SetCallback(void (B::*callback)(int)) { }
But then you need an instance of B to call your callback, e.g.:
B b;
(b.*callback)(2);

I'm using following code. It is not pretty, but you asking for C++03:
#include <iostream>
#include <vector>
#include <functional>
class AbstractCallback {
public:
virtual void call(int arg) = 0;
};
template <class T>
class Callback : public AbstractCallback {
public:
typedef std::mem_fun1_t<void, T, int> CallbackFunc;
private:
CallbackFunc func;
T* object;
public:
Callback(T* _object, const CallbackFunc& _func)
: object(_object), func(_func) {
}
void call(int arg) {
func(object, arg);
}
};
struct A {
void foo(int a) {
std::cout << "foo " << a << std::endl;
}
};
struct B {
void bar(int a) {
std::cout << "bar " << a << std::endl;
}
};
int main() {
A a;
B b;
AbstractCallback* cbs[2] = {
new Callback<A>(&a, std::mem_fun(&A::foo)),
new Callback<B>(&b, std::mem_fun(&B::bar)),
};
cbs[0]->call(10);
cbs[1]->call(22);
delete cbs[0];
delete cbs[1];
return 0;
}
As you can see pointer-to member functions (of type A::* and B::*) are wrapped into std::mem_funs and a Callback class which is generated for each type (A and B in this case).
This allows to keep method of any type in vectors, arrays or lists of abstract callbacks.

Related

C++ A class member function in a class member function's parameter? [duplicate]

I have written a small program where I am trying to pass a pointer to member function of a class to another function. Can you please help me and where I am going wrong..?
#include<iostream>
using namespace std;
class test{
public:
typedef void (*callback_func_ptr)();
callback_func_ptr cb_func;
void get_pc();
void set_cb_ptr(void * ptr);
void call_cb_func();
};
void test::get_pc(){
cout << "PC" << endl;
}
void test::set_cb_ptr( void *ptr){
cb_func = (test::callback_func_ptr)ptr;
}
void test::call_cb_func(){
cb_func();
}
int main(){
test t1;
t1.set_cb_ptr((void *)(&t1.get_pc));
return 0;
}
I get the following error when I try to compile it.
error C2276: '&' : illegal operation on bound member function expression
You cannot cast a function pointer to void*.
If you want a function pointer to point to a member function you must declare the type as
ReturnType (ClassType::*)(ParameterTypes...)
Further you cannot declare a function pointer to a bound member function, e.g.
func_ptr p = &t1.get_pc // Error
Instead you must get the address like this:
func_ptr p = &test::get_pc // Ok, using class scope.
Finally, when you make a call to a function pointer pointing to a member function, you must call it with an instance of the class that the function is a member of. For instance:
(this->*cb_func)(); // Call function via pointer to current instance.
Here's the full example with all changes applied:
#include <iostream>
class test {
public:
typedef void (test::*callback_func_ptr)();
callback_func_ptr cb_func;
void get_pc();
void set_cb_ptr(callback_func_ptr ptr);
void call_cb_func();
};
void test::get_pc() {
std::cout << "PC" << std::endl;
}
void test::set_cb_ptr(callback_func_ptr ptr) {
cb_func = ptr;
}
void test::call_cb_func() {
(this->*cb_func)();
}
int main() {
test t1;
t1.set_cb_ptr(&test::get_pc);
t1.call_cb_func();
}
In addition to Snps's answer, you could also use a function wrapper from C++11 to store a lambda function:
#include <iostream>
#include <functional>
class test
{
public:
std::function<void ()> Func;
void get_pc();
void call_cb_func();
void set_func(std::function<void ()> func);
};
void test::get_pc()
{
std::cout << "PC" << std::endl;
}
void test::call_cb_func()
{
Func();
}
void test::set_func(std::function<void ()> func)
{
Func = func;
}
int main() {
test t1;
t1.set_func([&](){ t1.get_pc(); });
t1.call_cb_func();
}

Call a C-style function address with std::bind and std::function.target using a method from object

I have a C-style function, which stores another function as an argument. I also have an object, which stores a method that must be passed to the aforementioned function. I built an example, to simulate the desired situation:
#include <functional>
#include <iostream>
void foo(void(*f)(int)) {
f(2);
}
class TestClass {
public:
std::function<void(int)> f;
void foo(int i) {
std::cout << i << "\n";
}
};
int main() {
TestClass t;
t.f = std::bind(&TestClass::foo, &t, std::placeholders::_1);
foo( t.f.target<void(int)>() );
return 0;
}
What is expected is that it will be shown on screen "2". But I'm having trouble compiling the code, getting the following message on the compiler:
error: const_cast to 'void *(*)(int)', which is not a reference, pointer-to-object, or pointer-to-data-member
return const_cast<_Functor*>(__func);
As I understand the use of "target", it should return a pointer in the format void () (int), related to the desired function through std :: bind. Why didn't the compiler understand it that way, and if it is not possible to use "target" to apply what I want, what would be the alternatives? I don't necessarily need to use std :: function, but I do need the method to be non-static.
This is a dirty little hack but should work
void foo(void(*f)(int)) {
f(2);
}
class TestClass {
public:
void foo(int i) {
std::cout << i << "\n";
}
};
static TestClass* global_variable_hack = nullptr;
void hacky_function(int x) {
global_variable_hack->foo(x);
}
int main() {
TestClass t;
global_variable_hack = &t;
foo(hacky_function);
return 0;
}
//can also be done with a lambda without the global stuff
int main() {
static TestClass t;
auto func = [](int x) {
t->foo(x); //does not need to be captured as it is static
};
foo(func); //non-capturing lambas are implicitly convertible to free functions
}

Passing an inherited method to another method

I am trying to build a class that has a member function with a method as argument. The methods are defined in inherited classes. I build a minimal example:
#include <iostream>
struct base
{
base() {}
int number(int (*f)(int))
{
return f(1);
}
};
struct option1 : base
{
int timesTwo(int i){return 2*i;}
option1()
{
std::cout << number(timesTwo);
}
};
struct option2 : base
{
int timesThree(int i){return 3*i;}
int timesFour (int i){return 4*i;}
option2()
{
std::cout << number(timesThree);
}
};
int main()
{
option1 a; //I would expect this to print "2"
}
The current syntax in the function number is for a general function, but I cannot get it to work for a method of any inherited classes.
The problem here is that you're passing a pointer to a member function, which is completely different from a pointer to a non-member function (which is what your number function takes as an argument).
You could use std::function and std::bind:
int number(std::function<int(int)> f)
{
return f(1);
}
...
number(std::bind(&option1::timesTwo, this, _1));
You could also use templates, and extra arguments, like
template<typename T>
int number(T* object, int(T::*f)(int))
{
return (object->*f)(1);
}
...
number(this, &option1::timesTwo);
Or the simple (but not always correct, depending on situation and use case): Make the callback-function static:
static int timesTwo(int i){return 2*i;}
My recommendation is that you look over the solution using std::function, because then it's easy to call the number function with any type of callable object, like a lambda:
number([](int x){ return x * 2; });
The given error says :
error: reference to non-static member function must be called
You can just add static before your method members.
And I would suggest you to use std::function instead of pointer functions.
A working code :
#include <iostream>
#include <functional>
struct base
{
base() {}
int number(std::function<int(int)> f)
{
return f(1);
}
};
struct option1 : base
{
static int timesTwo(int i){return 2*i;}
option1()
{
std::cout << number(timesTwo);
}
};
struct option2 : base
{
static int timesThree(int i){return 3*i;}
static int timesFour (int i){return 4*i;}
option2()
{
std::cout << number(timesThree);
}
};
int main()
{
option1 a; // now it works
}

Passing a pointer to a class member function as a parameter

I have written a small program where I am trying to pass a pointer to member function of a class to another function. Can you please help me and where I am going wrong..?
#include<iostream>
using namespace std;
class test{
public:
typedef void (*callback_func_ptr)();
callback_func_ptr cb_func;
void get_pc();
void set_cb_ptr(void * ptr);
void call_cb_func();
};
void test::get_pc(){
cout << "PC" << endl;
}
void test::set_cb_ptr( void *ptr){
cb_func = (test::callback_func_ptr)ptr;
}
void test::call_cb_func(){
cb_func();
}
int main(){
test t1;
t1.set_cb_ptr((void *)(&t1.get_pc));
return 0;
}
I get the following error when I try to compile it.
error C2276: '&' : illegal operation on bound member function expression
You cannot cast a function pointer to void*.
If you want a function pointer to point to a member function you must declare the type as
ReturnType (ClassType::*)(ParameterTypes...)
Further you cannot declare a function pointer to a bound member function, e.g.
func_ptr p = &t1.get_pc // Error
Instead you must get the address like this:
func_ptr p = &test::get_pc // Ok, using class scope.
Finally, when you make a call to a function pointer pointing to a member function, you must call it with an instance of the class that the function is a member of. For instance:
(this->*cb_func)(); // Call function via pointer to current instance.
Here's the full example with all changes applied:
#include <iostream>
class test {
public:
typedef void (test::*callback_func_ptr)();
callback_func_ptr cb_func;
void get_pc();
void set_cb_ptr(callback_func_ptr ptr);
void call_cb_func();
};
void test::get_pc() {
std::cout << "PC" << std::endl;
}
void test::set_cb_ptr(callback_func_ptr ptr) {
cb_func = ptr;
}
void test::call_cb_func() {
(this->*cb_func)();
}
int main() {
test t1;
t1.set_cb_ptr(&test::get_pc);
t1.call_cb_func();
}
In addition to Snps's answer, you could also use a function wrapper from C++11 to store a lambda function:
#include <iostream>
#include <functional>
class test
{
public:
std::function<void ()> Func;
void get_pc();
void call_cb_func();
void set_func(std::function<void ()> func);
};
void test::get_pc()
{
std::cout << "PC" << std::endl;
}
void test::call_cb_func()
{
Func();
}
void test::set_func(std::function<void ()> func)
{
Func = func;
}
int main() {
test t1;
t1.set_func([&](){ t1.get_pc(); });
t1.call_cb_func();
}

C++ Running a function pointer of class A from within class B as callback

I'm trying to run a method of one class from inside another class, I have a basic GUI that lets the user fill his name and password, and when it clicks the login button another takes over and handles the event, I would like to set a callback in case of a successful login, but I'm having problems sending the function pointer to my handler.
I made a raw example of what I'm trying to do.
#include <iostream>
using namespace std;
class LoginHandler {
public:
void loginAttempt(bool result)
{
if(result == true)
{
cout << "Login success! W00t!" << endl;
//Run my callback :)
callback();
} else {
cout << "Login failed." << endl;
}
}
void setCallback(void (*cb)())
{
callback = cb;
}
private:
void (*callback)();
};
class Foo {
public:
void run()
{
LoginHandler* loginHandler = new LoginHandler();
loginHandler->setCallback(&Foo::sayHello);
loginHandler->loginAttempt(false);
loginHandler->loginAttempt(true);
}
void sayHello()
{
cout << "You actually logged in! Isn't that amazing!?" << endl;
}
};
int main()
{
Foo foo;
foo.run();
return 0;
}
I'm getting the next error:
In member function 'void Foo::run()':
error: no matching function for call to 'LoginHandler::setCallback(void (Foo::*)())'
note: candidate is: void LoginHandler::setCallback(void (*)())
note: no known conversion for argument 1 from 'void (Foo::*)()' to 'void (*)()'
Thanks in advice.
Raw function pointers are mostly obsolete and should be used only for low-level performance-critical stuff. For the rest of us C++ has std::function which is infinitely better. It handles cases like yours with ease.
If you cannot use a it because you don't have a C++11 compiler, boost::function is a drop-in substitute.
You've specified that "setCallback" takes a function pointer, not a member-function pointer.
void setCallback(void (*cb)())
you are calling it - as the compiler complains - with a member-function pointer
loginHandler->setCallback(&Foo::sayHello);
In order to take a member function pointer, the setCallback definition is going to have to be able to determine what class to use, and the location where you call the callback is going to have to know what class so it can dereference the pointer.
Generally people solve this with a C-style callback handler, either
static FooSayHelloCallback(void* fooParam)
{
Foo* foo = static_cast<Foo*>(fooParam);
foo->sayHello();
}
or a functor object
struct LoginHandlerCallbackFunctor
{
void* m_this;
public:
FooSayHelloFunctor(void* this_) : m_this(this_) {}
virtual void operator()() = 0;
};
struct FooSayHelloFunctor : public LoginHandlerCallbackFunctor
{
public:
FooSayHelloFunctor(Foo* foo_) : LoginHandlerCallbackFunctor(foo_) {}
virtual void operator()() { ((Foo*)m_this)->sayHello(); }
};
Then
class LoginHandler {
...
LoginHandlerCallbackFunctor m_callback;
...
void setCallback(const LoginHandlerCallbackFunctor& functor)
{
m_callback = functor;
}
void doCallback()
{
m_callback(); // calls operator()
}
If you want to get really fancy you could maybe do that with templates.
Or, alternatively, you could use C++11 Lambdas and std::function.
class LoginHandler
{
typedef std::function<void(void)> GreetingCallback;
GreetingCallback m_callback;
...
void setCallback(const GreetingCallback& callback_)
{
m_callback = callback_;
}
void doCallback()
{
m_callback();
}
}
and in foo
LoginHandler loginHandler();
loginHandler.setCallback([=]() { sayHello(); });
loginHandler->loginAttempt(false);
loginHandler->loginAttempt(true);
sayHello should be a static function.
Because ordinary member functions have implicit parameter ¨this¨. So the full signature of sayHello is void sayHello(Foo* this);
Another way - use pointer to class member.
Also you can use functor structure instead of function.