circularity

circularity

Post by Mary K. Kuhn » Thu, 23 Nov 2000 04:00:00



Class A calls a function from class B.  Class B calls a function from class
A.
This means that A needs to see B in order to compile, and B needs to see
A.

If all of one's #includes are in the .h files, there is no way (as far as I
can see)
to get this to compile.  It can be compiled using #includes in the .cpp
files,
but this feels like a hack to me.  Is that how it's normally done?  Or is
the
standard advice to redesign until the situation is not circular?

A concrete example:

My program uses polymorphism to handle different types of data.  Several
objects need to be polymorphic on data type.  They are created by a
factory which knows the data type of the current part of the data set.

One of the created objects would like to know about the factory so that
it can request sub-objects as it needs them.  This introduces the circle.



      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

circularity

Post by Marcel van den Dunge » Fri, 24 Nov 2000 04:00:00




Quote:> Class A calls a function from class B.  Class B calls a function from
class
> A.
> This means that A needs to see B in order to compile, and B needs to see
> A.

// file: A.h

class B;    // forward declaration of B
class A
{
  // ...
  private:
    B *b;

Quote:};

// file A.cpp
#include "A.h"
#include "B.h"

// use B's public members from A's members

Class B is an incomplete type at the moment the compiler sees class A. As
long
as you only use pointers or references to B, the compiler doesn't need the
sizeof or
definition of class B, it is ok.
This is the way this is normally done. It also minimizes compiletime
dependencies.
When you change something in the headerfile where class B is defined, only
modules
that include "B.h" need to be recompiled, not those that include "A.h"

HTH,
Marcel


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

circularity

Post by Michiel Salter » Fri, 24 Nov 2000 04:00:00



> Class A calls a function from class B.  Class B calls a function from class
> A.  This means that A needs to see B in order to compile, and B
> needs to see A.

More precisely: The implementation of A needs to see the interface of B, and
vica versa. Being explicit here solves the standard problem later:

Quote:

> If all of one's #includes are in the .h files, there is no way (as far as I
> can see) to get this to compile.  It can be compiled using #includes
> in the .cpp files, but this feels like a hack to me.  Is that how it's
> normally done?  Or is the standard advice to redesign until the situation
> is not circular?

It shoudln't be a problem to get this to compile using include guards; a.h
includes b.h which includes a.h, at which moment the include guards break
the circle and a.h and b.h are both included once. However, this is not good
design. .h should represent an interface. If and only if the interface
of A requires the interface of B should a.h include b.h. But if the classes
are that tightly coupled they should share a header.

If it is only the implementation of A which needs the interface of B the
the implementation (.cpp) should include the interface (.h). This certainly
isn't a hack.

BTW, The interface of B* isn't the interface of B. Most of the interface of B*
can be obtained by writing class B;. This allows creation, assignment and
destruction of pointers to B, only not dereferencing. But an 'class A'
interface rarely needs that.

Quote:> A concrete example:
> My program uses polymorphism to handle different types of data.  Several
> objects need to be polymorphic on data type.  They are created by a
> factory which knows the data type of the current part of the data set.
> One of the created objects would like to know about the factory so that
> it can request sub-objects as it needs them.  This introduces the circle.

In that case, the implementation of the data set object needs an factory
interface, and the factory implementation only needs the data set interface.
So all is fine and implementable, no dependancy circle is introduced
(as long as the set of sub-objects is bounded.)

HTH,
--
Michiel Salters



      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

circularity

Post by Gerhard Menz » Fri, 24 Nov 2000 04:00:00



> Class A calls a function from class B.  Class B calls a function from
> class A. This means that A needs to see B in order to compile, and B
> needs to see A.

Highly undesirable.

Quote:> If all of one's #includes are in the .h files, there is no way (as far
> as I can see) to get this to compile.  It can be compiled using
> #includes in the .cpp files, but this feels like a hack to me.  Is
> that how it's normally done?  Or is the standard advice to redesign
> until the situation is not circular?

> A concrete example:

> My program uses polymorphism to handle different types of data.  
> Several objects need to be polymorphic on data type.  They are created
> by a factory which knows the data type of the current part of the data
> set.

> One of the created objects would like to know about the factory so
> that it can request sub-objects as it needs them.  This introduces the
> circle.

I don't know what *the* standard advice is, but my standard advice is to
break the circle with an extra abstract base class:

   class AbstractA
   {
   public:
      virtual void fa () = 0;
   };

   class B
   {
   public:
      void fb ();
      void callA (AbstractA& a) { a.fa (); }
   };

   class A : public AbstractA
   {
   public:
      virtual void fa ();
      void call B (B& b) { b.fb (); }
   };

Change access levels etc. according to your needs.

Which of the two classes should be derived from the additional interface
depends on which class has more knowledge about the other. In your
case,   I would say that a factory typically knows more about the
objects it creates than the other way round, hence I would provide the
factory with an extra, more narrow base class interface that is passed
to the creatures desiring to produce offspring of their own.

There are situations where it might be even better to derive both
classes involved from an abstract base class. The Observer pattern is a
good example.

Gerhard Menzl


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

circularity

Post by Gerhard Menz » Sat, 25 Nov 2000 04:00:00



>    class A : public AbstractA
>    {
>    public:
>       virtual void fa ();
>       void call B (B& b) { b.fb (); }
>    };

The second member function should read

   void callB (B& b) { b.fb (); }

of course. Sorry for the stray blank.

Gerhard Menzl


      [ about comp.lang.c++.moderated. First time posters: do this! ]

 
 
 

1. A circularity in Alife methodology?

There is an element of question begging in any effort to construct
artificial life.  By asking "Is artificial life possible?" you beg the
question "Is life possible?".  

I know of no coherent definition of life - which I attribute to the fact
that life is not a coherent concept.

It IS inconsistent (though not paradoxical) to suggest that the necessary
properties of life can be discovered by constructing life.  Ironically,
AL appears to be biocentic in a way - when the only models of living
things you have are biological you must measure your success by how
closely the artefact matches the model.  It is just true that we (humans)
revert to ostensive definition when trying to explain life.  That is, we
explain by analogy:  when asked "What is a living thing?", we point to a
biotic thing and say "It's one of those".

Don't get me wrong.  I believe a machine could think.  After all, I am a
machine and I think.

Nigel Stobbs
Department of Philosophy
University of Queensland

2. Disable mapping drive

3. Measuring Robot: Circularity

4. Information on Sun Hardware IPX or similar

5. Circularity in Interface-References

6. Error : HidD_SetFeature

7. Avoiding circularity in symbol manipulation

8. Graphic simulations

9. Determining circularity

10. TR on Circularity Problem for Attribute Grammars