Jump to content
  • Advertisement
Sign in to follow this  
s73obrien

Class-to-class callback?

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

If you intended to correct an error in the post then please contact us.

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 this post


Link to post
Share on other sites
Advertisement

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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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 this post


Link to post
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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!