7

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?

asked Jul 26, 2016 at 10:14

3 Answers 3

7

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.

answered Jul 26, 2016 at 11:16
6
  • +1 for the tell don't ask point. Commented 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? Commented 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/… Commented 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. Commented 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. Commented Jul 26, 2016 at 18:52
4

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.

answered Jul 26, 2016 at 16:56
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.

answered Jul 26, 2016 at 16:17

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.