6

I have a class "Parent". "Parent" class creates an object of class "Child" in my CPP module. The use-case is "Child" has to request for some information from "Parent". This can be done in several ways and I can think of the following designs.

1) Store object pointer/reference of "Parent" in "Child" and let "Child" call some public method of "Parent".

2) "Child" exposes an API to register callbacks. "Parent" registers a static function with "this" pointer as callback handle. When "Child" wants to request for information, it will call the registered callback function with callback handle as one of the arguments. The callback function will dereference the callback handle to "Parent" object and get the information.

Can someone tell me which is the better design? Also I would like to know is there any standard design for this type of problem?

3 Answers 3

5

It probably depends on how tightly you want your objects to be coupled. But for faster development and more readable code I think the method 1 is preferable. Just store the reference to parent as a weak pointer (assuming you use modern C++).

You could do some pattern in which the parent would register a function within the child (in this case prefer closures and std::function to bare function pointers). But if these two objects are the only ones that will need to share the information then I see no point of not giving a pointer to parent to the child object, this is used quite often.

Finally, best would be to have a uni-directional data flow if it is possible. Rather than making the child ask for information, make the parent push it inside. This will make the interface more readable and safe (because the parents always knows whether it is safe to send data but the child might not be aware of the parent's state). It also makes it easier to have all data passed as constant values.

5
  • +1 for the tell don't ask point. Jul 26, 2016 at 12:15
  • Thank you @Jozef Legény!! Yes, I agree that it is good to have data flow in one direction. I am just curious and I have one more question related to method 2. Generally I have seen callback functions are normal C-style functions with "this" pointer as callback handles. Is there any specific reason for that? Why can't one register a public non-static class function as callback function?
    – MayurK
    Jul 26, 2016 at 14:30
  • Prior to C++11 you could only pass around pointers to C functions (not bound to an object). So in order to have a callback you either had a function which receives a pointer to "this" every time it is called, or you passed in a function disguised as an object (basically an object with a single run() method). Now in C++11 you can pass object methods as callback using std::bind. For more information look here: stackoverflow.com/questions/15264003/… Jul 26, 2016 at 14:39
  • 1
    @JozefLegény: "Prior to C++11 you could only pass around pointers to C functions (not bound to an object)." Nonsense. std::function and std::bind come from the equivalent Boost features. So yes, you could do all of those things in C++98/03. They just weren't part of the standard library. Jul 26, 2016 at 18:18
  • @NicolBolas yes of course. But I think that there are mainly two reasons why these were less used. a) most APIs are still made to be C-compatible b) using boost is (or is perceived as, YMMV) a burden. Having the functionality in standard library is always better. Jul 26, 2016 at 18:52
3

The pointer to the parent is a valid approach. But it's a very specific solution that will be difficult to extend.

A nicer approach could be to implement the observer design pattern. There are plenty of examples how to do it; to start with the GoF reference book, or here. This is in fact a general clean form of your option 2 (parent is observer, child is subject).

If you nevertheless prefer the callback approach, I'd suggest to opt for a callback objects.

1

Try something object oriented.

Pass the child an interface that the parent implements. Since this does create a cyclic data structure, you just have to free things in the right order; something we don't worry about in other languages...

You may find that the child only needs access to the parent (interface) at certain well-known times, so maybe you can provide that as a parameter to a child method rather than as a parameter to the constructor.

Otherwise, if the child needs to respond to changes in the parent consider the Observer pattern.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.