Boost logo

Boost :

From: Michael Goldshteyn (mgoldshteyn_at_[hidden])
Date: 2005-11-16 13:56:00


Description:

I have a class hierarchy which unfortunatelly results in circular
dependencies not allowed by C++. Is there any simple way to fix this? Please
note, I have trivialized this problem for the purpose of illustration. The
actual code that needs this is far more complex. I am quite perplexed,
please help:

Here is the code made as simple as I can:

part.h
------
class Part
{
};

action.h
--------
// The Action class is where the problem arises. It depends on an iterator
in a class which is not yet defined.
// The class cannot be defined before the Action class, because it depends
on the definition of the Action class.
class Action
{
public:
  typedef std::list<Part> PartsList;

private:
  // I want a back "reference" to the iterator pointing to
  // the part for which this action applies. This is OK, I can just
  // typedef PartsList myself and don't need Whole for this
  PartsList::iterator iPart;

  // I also want a back "reference" all the way to the iterator
  // in the NameWholeMap for whose value this action applies
  // Here, I have a circular reference issue.
  // Note: Storing the key in the NameWholeMap to eliminate
  // this problem is not an option. I need a direct reference back
  // to the association in the map (map iterator), so as not to have
  // to look it up again.
  NamedWholes::NameWholeMap::iterator iNamedWhole;
};

whole.h
--------
// Whole is basically a container of Parts. Action needs an iterator to the
list it contains.
// Fortunatelly, because the value in this list (i.e. Part) does not depend
on Action, I can just
// type define the same list (i.e. PartsList) in the Action class and refer
to its iterator there.
class Whole
{
public:
    typedef std::list<Part> PartsList;
    typedef boost::optional<Action> OptionalAction;
    typedef std::vector<Action> Actions;

    void GetActionsOnSomePartsForThisWhole(Actions &actions);

private:
    OptionalAction DecideOnAction() const;

    Parts m_parts;
};

namedwholes.h
----------------
// This is the other half of our circular reference problem. This class has
a function which gathers
// actions on various parts contained in various wholes contained in its
NameWholeMap. Those
// actions would like to know directly which iterator in the NameWholeMap
they were created
// from, so as not to require a search by key later.
// The problem is that this class must know how Action is defined and Aciton
must know how
// this class is defined, creating a circular reference.

class NamedWholes
{
public:
    typedef std::map<std::string,std::Whole> NameWholeMap;
    typedef Whole::Actions Actions;

    void GetAllActions(Actions &actions);

private:
    NameWholeMap m_nameWholeMap;
};


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk