7

I do this a lot:

class Child{
  Control*parent;
public:
  Child(Control*theParent):parent(theParent){}
 };

class Control{
 Child child;
 void makeChild(){ child=Child(this); }
 //Control() : child(this) { }  //another example
 }

So the Control owns and operates the child, but the child still has reference to the parent Control.

When I read general topics on program design patterns, etc, it seems like this method of organizing objects is not particularly recommended. I realize there are risks, for example you don't want your child to abuse its parent by making its parent do things that only the parent should decide to do on its own; in which case, seems easy to prevent by making sure the parent's critical methods are private. But then you might have another controller that manages the parent, in which case some methods should be public, and now your child has access to those too, when really only some other controller should manipulate those.

So I can see how this can be dangerous.

But my question is, what is a common alternative? You need a parent to own a child, but you need the child to be able to notify the parent of things occasionally. How, if not the above?

Objective-C has the NSNotificationCenter which allows notifications without actually passing references, but this also makes it easy to create organizational problems (why is my child sending out this notification, and who is going to receive it?)

johnbakers
  • 24,158
  • 24
  • 130
  • 258

4 Answers4

3

You can separate them by an interface:

class IListener {
public:
    virtual void notify (int somevalue) = 0;
    ~IListener() {};
}

class Child{
private:
    IListener *listener;
public:
    Child(IListener *theListener):listener(theListener){}
};

class Control: public IListener {
private:
    Child child;
public:
    makeChild(){ child(this) };
    virtual void notify(int someValue) { doSomething(someValue);};
}

(This is a simple version of the observer pattern, BTW).

Mikkel
  • 3,284
  • 2
  • 18
  • 20
  • 1
    Your `notify` in the base class should be `virtual` but otherwise this seems good – maditya Apr 10 '13 at 06:51
  • Thanks. I have been writing too much Java lately. – Mikkel Apr 10 '13 at 07:00
  • 1
    I would prefer using an adapter with delegation over inheritance, and provide a narrow control interface rather than a generic observer, but otherwise this is the way I would go (c: – Peter Wood Apr 10 '13 at 07:14
  • @BillyONeal: not necessarily, and `-Wdelete-non-virtual-dtor` will warn about any issue anyway. – Matthieu M. Apr 10 '13 at 08:46
  • @PeterWood I would enjoy some elaboration on the suggestion you make, perhaps as another answer. – johnbakers Apr 10 '13 at 11:14
  • @MatthieuM Yes necessarily. Not everyone is using GCC. Either allow deletion by pointer by making the destructor virtual, or explicitly disallow by making it protected. There's no reason to make a base class behave any other way. – Billy ONeal Apr 10 '13 at 18:14
  • @BillyONeal: Actually, I implemented it in Clang first and the gcc folks pillaged it ;) But I guess MSVC might be lagging behind there :x – Matthieu M. Apr 10 '13 at 18:40
  • @Matthieu: Yes, EDG and ICC are lagging behind too by that metric. – Billy ONeal Apr 10 '13 at 19:00
2

It sounds like you are looking for the observer pattern.

In the observer pattern, an object maintains a list of dependents (aka observers) and notifies them of changes as required. In your case, the Control class is the observer and the Child class is the notifier.

The Boost library has a signal/slot mechanism that can be used to implement this: http://www.boost.org/doc/libs/1_49_0/doc/html/signals/tutorial.html#id3137144

There's an example of using this on SO: Complete example using Boost::Signals for C++ Eventing

Community
  • 1
  • 1
maditya
  • 8,626
  • 2
  • 28
  • 28
  • Interesting idea; I'd have thought there'd be a way to do something in the core language though. – johnbakers Apr 10 '13 at 06:45
  • Not yet, but I've heard it will be discussed for C++14. – maditya Apr 10 '13 at 06:46
  • Check out the other answer for an example of observer pattern without boost in c++ – johnbakers Apr 10 '13 at 06:48
  • If what you're going to use this for is not too complicated and won't change too much, I'd recommend taking a look at Mikkel's answer for a purely "core" implementation – maditya Apr 10 '13 at 06:48
  • Btw there are some differences ... in the Boost version, I believe the signal/slot mechanism is achieved entirely using templates, i.e. no inheritance. So there is no runtime overhead. This may or may not matter to you. – maditya Apr 10 '13 at 06:52
  • @SebbyJohanns: *The* other answer has the same issue as *The 3rd* answer, since answers keep appearing and are re-ordered live according to their score, any such reference soon becomes ambiguous. Baring deletion, it is best to refer to answers by their author's name (for friendly references) or directly by linking. – Matthieu M. Apr 10 '13 at 08:49
0

Throwing another idea in the ring, it would seem that a Friend class can go a long way with this as well.

Methods that a child should not have access to are made private or protected. That way the child cannot do any damage you don't want it to do.

Then if you need another class to manage your parent controller, your parent class makes that other class a friend so it can access all those private methods you withhold from the child.

johnbakers
  • 24,158
  • 24
  • 130
  • 258
0

When I read general topics on program design patterns, etc, it seems like this method of organizing objects is not particularly recommended.

This is so wrong, because of inversion of control. You could have created it as Child's member variable. Martin Fowler has a very nice article explaining one kind of inversion of control (dependency injection).

Here is an example explaining briefly how to implement dependency injection (dependency injected through constructor) :

#include <iostream>

struct B
{

    virtual ~B(){}
    virtual void foo() = 0;
};
struct A1 : public B
{
    virtual ~A1(){}
    virtual void foo()
    {
        std::cout<<"hello"<<std::endl;
    }
};
struct A2 : public B
{
    virtual ~A2(){}
    virtual void foo()
    {
        std::cout<<"test"<<std::endl;
    }
};

struct C
{
    C( B &b_ ) : b(b_){}

    void bar()
    {
      b.foo();
    }

    B &b;
};

#define SAY_HI

int main()
{
#ifdef SAY_HI
    A1 a;
#else
    A2 a;
#endif
    C c(a);

    c.bar();
}

If you think about design patterns, you'll notice some of them use some kind of inversion of control. Here are some well-known (from this link) :


By the way, what you have is called chain of responsibility.

BЈовић
  • 62,405
  • 41
  • 173
  • 273
  • essentially what I've demonstrated is dependency injection so can you explain what you mean when you say i'm doing it "wrongly"? your example is also injection, via constructor. that is included in my example too as an example. – johnbakers Apr 10 '13 at 11:19