Class-to-class callback?

This topic is 2880 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

Okay, this is likely a repost, but it's an important topic, and one that is a huge stumbling block for me.

I have a class (It's name is Class_A in this post ) that needs to callback to a member function of another class (Class_B), like so:

 void Class_A::member_function() { ... //do stuff this->pointer_to_Class_B_function(this); } 

The function in Class_B needs to have access to both Class_A and Class_B (which means I can't just use static for the Class_B func)

My question is: What is the best way of going about this? I'd like to have it so I don't have to modify Class_B in any specific way to 'fit' Class_A, if possible. Class_A is a COM object, if that helps...

Share on other sites

Okay, this is likely a repost, but it's an important topic, and one that is a huge stumbling block for me.

I have a class (It's name is Class_A in this post ) that needs to callback to a member function of another class (Class_B), like so:

 void Class_A::member_function() { ... //do stuff this->pointer_to_Class_B_function(this); } 

The function in Class_B needs to have access to both Class_A and Class_B (which means I can't just use static for the Class_B func)

My question is: What is the best way of going about this? I'd like to have it so I don't have to modify Class_B in any specific way to 'fit' Class_A, if possible. Class_A is a COM object, if that helps...

Declare a function as friend function to both of these two classes.

Share on other sites
I'm not sure I understand the problem. If A and B are tightly coupled in that B needs to talk to A's interface, then so be it; the code you have is the correct approach.

Better said: you don't actually have a problem here, as stated. If there's more to this, it'd be helpful to know the context and why exactly you feel there is an issue; if it's just a matter of "A and B are interdependent" then think for a minute about whether or not you really care that they are interdependent. (Tight coupling is, occasionally, a perfectly good solution to a problem.) If you do care, fix your design so A and B are not coupled. If you don't, then take off early and have a beer ;-)

Share on other sites
I apologize for the lack of context, ApochPiQ. I am reluctant to divulge too much, as I am dealing in the realm of the proprietary w/ this project. Here's some more

Class_B is an application class. It holds information on the creation of a window (this is a Win32 project atm btw) and processing of its messages, along with other application-specific information.
I have defined a user-interface callback inside that class that is called by Class_A at the completion of a particular task to update the window held by Class_B. Class_A, as stated before, is a COM object. It is instantiated and used from within Class_B.

The problem is, because I am using a callback mechanism, I am currently forced to use a static member of Class_B as the callback. This, of course, makes it so Class_A cannot pass in the pointer to Class_B when making the call (as, I admit, it should probably be). The callback function has the permission to access Class_B (since it *is* a member function of it), it just doesn't know where to look. The callback function also has to be able to access Class_A's interface to retrieve the information, which can (and is) achieved through a simple pointer argument. Since Class_A is a component that I'd like to reuse, I want to keep coupling to an absolute minimum.

I have found a solution in passing the handle to the window to the callback and then using that handle to retrieve Class_B's pointer from an OS-dependent variable cache associated with said window, but I really really want to stay away from any dependency on any OS in Class_A's code, as this will likely be ported at some point in the future. Also, it feels very clunky and inefficient and I was hoping that mayhaps there was a language feature that I wasn't aware of to achieve the desired results.

Using a friend function to both classes is a bit of an option, but that means I would have to declare a specific function name inside Class_A, effectively locking the app programmer into using that particular function name, which I simply will not do.

I appreciate any and all help on this.

Share on other sites
Does your callback mechanism let you provide custom contextual data, eg. via a void* or a pUnknown or something similar?

Share on other sites
Yeah, it does. That's how I pass in the pointer to Class_A. Unfortunately, at the time of execution, Class_A knows nothing about Class_B, so cannot pass in a pointer to it.

Basically, I've come to the conclusion that the function in Class_B has to either: use a this-style reference to itself (which is precluded by the enforced usage of a static member function) or produce a pointer to itself out of thin air. I have chosen the latter. It works, but I would still rather have the former.

Share on other sites
This really doesn't make much sense to me... how do you know what Class_B instance to operate on at the time of the callback invocation, but not when the callback is set up?

Share on other sites

Yeah, it does. That's how I pass in the pointer to Class_A. Unfortunately, at the time of execution, Class_A knows nothing about Class_B, so cannot pass in a pointer to it.

Basically, I've come to the conclusion that the function in Class_B has to either: use a this-style reference to itself (which is precluded by the enforced usage of a static member function) or produce a pointer to itself out of thin air. I have chosen the latter. It works, but I would still rather have the former.

To edit this for clarity: Class_A doesn't know about Class_B at the time of executing the callback. At one point, when telling A about the callback function, I do have the opportunity to pass in a pointer to B, but there is no way to make it type-safe, since A isn't supposed to know the details of B, so instead, I pass in a pointer-to-static-member for B using a predefined function signature. A small example program to illustrate:

 #include <iostream> class Class_A { void run(); void set_callback(void (*)(void*)); private: void (*callback)(void*); }; void Class_A::run() { this->callback(this); } void Class_A::set_callback(void(*func_to_callback)(void*)) { this->callback = func_to_callback; } class Class_B { static void func_to_be_called(void*); }; void Class_B::func_to_be_called(void* pointer_to_A) { //do stuff with Class_A and Class_B std::cout << "Callback function called" << std::endl; std::cout << "Class_A = " << (long)pointer_to_A << std::endl; //notice that Class_B cannot be accessed because this is a static function //and pointer to B is not passed in } int main() { Class_A A; Class_B B; A.set_callback(B.func_to_be_called) A.run(); return 0; } 

Looking at this simplified example, I think I see what you are saying in that I could pass in a pointer to B when setting the callback. I suppose that'll probably work, as long as Class_A doesn't have to *do* anything with said pointer, just pass it into the callback. I now see the error of my ways, thank you

Share on other sites
Callbacks often use void* for precisely this kind of thing :-) You can simply store both the callback target function and the target B instance (in a void*) and you're done.

A much cleaner approach is to have B derive from an interface that A understands. Then A can call the function directly without a function pointer involved at all. This makes the link explicit and allows you to easily understand what sorts of classes might take the role of "B" - i.e. only those that implement the callback interface needed for talking to A.

Since you mentioned COM, a perfect option here is to pass the B pointer into A using a pUnknown, then QueryInterface to obtain a compatible callback interface, and invoke that.

Share on other sites
Your second suggestion worked beautifully, once I figured out I had to specify that the callback class is virtual in Class_B's declaration. I think I'll try elevating this to a COM-based solution in the near future, but first, I have to go back and fix up the way I've been using callbacks throughout (been using exclusively C-style callbacks). Yet another casualty of my programmatic upbringing as a procedural coder

Thank you very much for your help ApochPiQ. I knew there was a better way to do it, just wasn't sure how.

• Game Developer Survey

We are looking for qualified game developers to participate in a 10-minute online survey. Qualified participants will be offered a \$15 incentive for your time and insights. Click here to start!

• 11
• 15
• 21
• 26
• 11