tags:

views:

57

answers:

5

Hi,

This is a general design question from C++ perspective. I have a container class which contains objects of 2 other classes.

From container class we can call methods of the contained class object "as we have handle to the contained class object" e.g. objContainedClass1->SomeMthod();

But I want to know how would the contained class object (objContainedClass1) access methods of container class.

I can think of following ways:

  1. The container class object passes the pointer to itself (this pointer) to the contained class constructor. Using this pointer, the contained class can access the methods of container class.

  2. Make some functions in the container class as static.

Any more ideas of achieving this?

Thanks

+6  A: 

Don't, typically it is bad design for a class to have to know about its container. Usually it means you have broken the single responsibility principle.

stonemetal
I don't really see how bidirectional associations have anything to do with the single responsability principle. I can think of many cases where bidirectional associations are useful if not mandatory. For example, in tree structures (cf. Composite), it is often useful to have a reference to the parent in a node.
Luc Touraille
It rather depends on the situation. In a graph knowing about other nodes isn't a big deal. However most other cases it is a bad idea. Sockets shouldn't know about the FD_SET they are in, and if your implementation does it is because your sockets are doing more than one thing aka violating SRP. So it isn't an automatic no don't but 9 times out of 10 it isn't the right thing to do. Most of the time when I see it the container is being a container and doing something else where it should just contain another peer.
stonemetal
I wish I could remove my downvote, since your comment now adds the nuance that I thought was lacking in your answer, but it is no longer possible :(.
Luc Touraille
A: 

Both ways are OK for different purposes. If all you need is to call static methods, #2 is OK. But if you need to access instance methods of container class, you need to have container class pointer, so #1 is the way.

In the case you need generic solution, implement observer pattern. In this case contained class doesn't know anything about container, it just raises events when necessary.

Alex Farber
+1  A: 

There are a number of bad-to-worse options.

You could make the contained classes part of the container class, if they are not used outside it.

You could make the container a friend of the contained classes (yuck).

You could pass in a reference or boost::shared_ptr to the container instead of a raw pointer. The best method depends on the lifetimes of each. Avoid raw pointers if you can.

What I would actually try to do is to isolate the interface of the container methods that the contained objects need to use (IContainerCallback, say), and use that as the link between the two. So the contained objects reference the container only indirectly, via an interface class that is decoupled from the implementation of the container.

Steve Townsend
A: 
  • Make some functions in the container class as static.

That's what can be called "goodbye OOP!" option and I refrain from using it as much as possible.

  • The container class object passes the pointer to itself (this pointer) to the contained class constructor. Using this pointer, the contained class can access the methods of container class.

Provided that the containing class implements an interface and contained classes know only the interface, I personally do not see any problem. In fact that is what I do myself. Obviously one has to be aware of the approach's gotchas, when e.g. contained object calls container's method during destruction of the latter (or any other moment of time when the container is in an intermediate state).

To further decouple the contained from the containing classes, events or messages could be used too. Contained objects do not know where they are contained, but instead send messages. Containing object when creating the contained objects registers itself as the recipient of the messages from them. That technique allows to make the objects literally independent, but requires (1) some messaging framework, (2) due to static nature of C++ rather elaborate to implement and (3) also needs additional level of documentation as interface of classes now includes messaging.

Otherwise, think twice why contained objects need to call container's methods. Could it be that you need to split off the container some generic functionality into 3rd class? If the contained objects are indeed the active objects and are the logical source of events in the system, then you might really need some basic event/messaging system to allow the container to efficiently poll for/monitor state changes in the contained objects.

Dummy00001
A: 

Don't. The responsibility of a container class is to contain things, nothing else. If you need your container class to take actions based on what's contained within, have a third object perform those actions. For instance, I'm assuming that you're rearranging or otherwise modifying the collection of classes based on the contents of the classes. Instead of attempting to do so within the contained classes, perform this action in a class which uses the container as a dependency.

EricBoersma