Reputation: 205
I am trying to call a member function, possibly given the object pointer, without knowing what class the member function is from. Is this possible?
Basically I want something like the following to work.
class Foo{
public:
Foo(void* object): obj(object) {}
void callFunc(void (*func)()){
obj->*func();
}
private:
void* obj;
};
class Bar{
public:
Bar(): foo(this) {}
void callSomeFunc(){
callFunc(someFunc);
}
void someFunc(){
cout << "hi\n";
}
private:
Foo foo;
};
int main(){
Bar bar;
bar.callSomeFunc();
return 0;
}
Upvotes: 7
Views: 1882
Reputation: 35164
Although I find the solution provided by @skypjack more elegant, here a solution that templates the Foo
-class (not "only" the function) as a whole. Thereby the type of obj
is known throughout the Foo
-class, which might be an advantage (or may be not).
Further, see also a solution that stores the member together with the associated object. Maybe it's helpful in some way:
#include <functional>
#include <iostream>
template<class T>
class Foo {
public:
Foo(T& obj) : _obj(obj) {}
void callFuncOnObj(void (T::*func)(void)) {
auto fn = mem_fn(func);
fn(_obj);
}
private:
T &_obj;
};
class Bar{
public:
Bar() : d(*this) {}
void callSomeFunc(){
d.callFuncOnObj(&Bar::someFunc);
}
void someFunc(){
cout << "hi Bar1\n";
}
private:
Foo<Bar> d;
};
class Foo2 {
public:
Foo2(std::function<void(void)> f) : _f(f) {}
void callFunction() {
_f();
}
private:
std::function<void(void)> _f;
};
class Bar2{
public:
Bar2() : d(std::bind(&Bar2::someFunc,this)) {}
void callSomeFunc(){
d.callFunction();
}
void someFunc(){
cout << "hi Bar2\n";
}
private:
Foo2 d;
};
int main(){
Bar bar;
bar.callSomeFunc();
Bar2 bar2;
bar2.callSomeFunc();
return 0;
}
Upvotes: 0
Reputation: 69922
It's an XY problem. Use a std::function
and/or a lambda.
#include <functional>
#include <iostream>
class Foo{
public:
template<class F>
void callFunc(F&& f){
f();
}
};
class Bar : public Foo{
public:
Bar(): foo() {}
void callSomeFunc(){
this->callFunc([this]{ someFunc(); });
}
void someFunc(){
std::cout << "hi\n";
}
private:
Foo foo;
};
int main(){
Bar bar;
bar.callSomeFunc();
return 0;
}
Upvotes: 1
Reputation: 50568
It looks a lot like an XY-problem. Anyway, let's try to reply to your question as it is.
A function member is bound to the type of the class to which it belongs, unless it's a static one (the latter is treated just like a plain function pointer and you don't even have to pass a pointer to an instance to call it).
Therefore you can make callFunc
a function template and let it deduce the type for you:
template<typename T>
void callFunc(void (T::*func)()){
(static_cast<T*>(obj)->*func)();
}
See it up and running on wandbox.
Note that you can incur in errors when you static_cast
your obj
if its original type (the one you erased to put it in a void *
) isn't T
.
Here is the full code you can see at the link above:
#include<iostream>
class Foo{
public:
Foo(void* object): obj(object) {}
template<typename T>
void callFunc(void (T::*func)()){
(static_cast<T*>(obj)->*func)();
}
private:
void* obj;
};
class Bar{
public:
Bar(): foo(this) {}
void callSomeFunc(){
foo.callFunc(&Bar::someFunc);
}
void someFunc(){
std::cout << "hi\n";
}
private:
Foo foo;
};
int main(){
Bar bar;
bar.callSomeFunc();
return 0;
}
Upvotes: 5