Reputation: 10286
I have a class A that should call a non-static class method from an interface class B, with signature expressed by, say, the following function pointer:
bool (B::*check)(int) const
Such method would be implemented by a set of classes {C} implementing B, each with multiple methods matching the above signature. I therefore need to bind the callback from A towards B, which in turn would delegate to the chosen method from C.
Edited with some code:
This is a sketch of what I have in mind. Beware that this is only an example of the requirement above, nothing in the organization of the code is mandatory outside, perhaps, class A.
class B {
public:
bool check(int val) const {
// call to a binded method with a given signature (sig) on a Cx class
...
}
};
class C1: public B {
...
// a method implementing the (sig) signature
// another method implementing the (sig) signature
};
class C2: public B {
...
// a method implementing the (sig) signature
// another method implementing the (sig) signature
};
class A {
public:
...
private:
bool result;
int val;
void call_check(B const& b) const {
result = b.check(val);
}
...
};
It that possible in C++? Or equivalently, what would be a solution that allows A to know of class B only?
To my puzzlement, I haven't found a solution around for this very specific need.
Upvotes: 0
Views: 1121
Reputation: 64730
Massive Edit
I think I got what you want, based on some heavy type-casting.
Note that I do NOT recommend this technique. Although my example works, I believe there are some big pitfalls here that could really screw things up.
As before, Class A
can accept both a method of the proper signature and an object (of type B
, or derived from type B
, such as your C
classes), and call the specified method on the specified object.
Class B
does not actually have any methods at all, and only acts as a common base-class for the two classes C1
& C2
.
At the bottom is a main
that demonstrates how this is used. I left out the implementation of the two SetCallback***
methods, as they're trivial.
class B
{ public: // Has nothing, only serves as base-class for C1 and C2.
};
class C1: public B
{
public: bool DoThis(int x) const { return true; }
};
class C2: public B
{
public: bool DoThat(int x) const { return false; }
};
class A
{
private:
bool (B::*m_check)(int) const;
B* m_Obj;
public:
void SetCallbackFunction(bool (B::*fnc)(int) const)
{ m_check = fnc; }
void SetCallbackObject(B* pB)
{ m_Obj = pB; }
bool InvokeCallback(int val)
{
return (m_Obj->*m_check)(val);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A a;
C1 c;
bool (C1::*func)(int) const;
bool (B::*b_func)(int) const;
func = &C1::DoThis;
b_func = (bool (B::*)(int) const)(func); // Dangerous Typecasting. Use caution!
a.SetCallbackFunction(b_func);
a.SetCallbackObject((B*)(&c)); // A simpler, safer typecast.
a.InvokeCallback(5); // Ends up calling C1::DoThis.
_getch();
return 0;
}
Upvotes: 1
Reputation: 5949
Pointers-to-member-functions are available, and do exactly what you want. However, just be aware that they are not actually "pointers", but are "pointer-like", since it is possible that proper lookup/calling must go through the "vptr" table(s) associated with a class that may possibly have more-than-one-parent.
In short: Yes, you can have it. If you implement in a template, you do not need to include the target headers (but you would need to implement the target class headers at the point of code expansion). If you implement as a non-template, then you could forward-declare the member functions and get it to work. Or, you could simply include the target class-type headers.
Since multiple target functions are available, yes, at the point of actual binding, you must include the header (you don't need the header if this is a template implementation):
class MyA {
public:
bool foo1(int) const;
bool foo2(int) const;
};
void MyFunc(void) {
bool (MyA::*my_ptr_to_func)(int) const;
my_ptr_to_func = &MyA::foo2;
MyA my_a;
// call it
if((my_a.*my_ptr_to_func)(42))
{
// ...
}
}
[UPDATE], based on your updated code, it seems like you merely want to make "bool B::check(int) const
" to be "virtual
" in the base class, and override/re-implement that function in the derived "C1
" and "C2
" classes?
Yes, the virtual
function will be called (the implementation in the C1
and C2
classes), even though your pointer was originally to the B::check(int)
function. This works, and is exactly why a pointer-to-member-function is not exactly a pointer, but is pointer-like (to permit your call to correctly execute the virtual
code in the derived classes).
So, no fear: It will work, just put "virtual
" on B::check(int)
in the base.
Upvotes: 1
Reputation: 208466
The simplest thing you can do is not to use a member function pointer, but rather a higher order construct like function
(either boost
or C++11) and register the callbacks with bind
(again, boost
or C++11).
Upvotes: 1
Reputation: 39354
It sounds like you want to use the observer pattern to allow A to hold a vector of function pointers of type bool (B::*check)(int) const
.
Classes in {C} could thus register through the observer pattern to A. I don't see why you need an interface, B, explicitly if you use this form of pattern. The interface will be guaranteed by the vector of function pointers requiring the signature of your chosen function pointer.
Upvotes: 0