You need to realize that a circular dependency implies that you can use only the corresponding circular dependent classes together: if you have a circular dependency between, say, A
and B
, you cannot use A
or B
independently in any program. To stick with your problem: surely, you don't need the other two friends to exist! All you need is some way to refer to some and interact with them in a way which may be constrained over their actual abilities.
However, it often is possible to have objects of classes use each other without cause a circular dependency. To this end it is important to determine what actually causes a dependency between two class/components (these are not entirely equivalent but providing a thorough definition would be somewhat lengthy). A
depends on B
under these conditions:
- When
A
contains a member of type B
.
- When
A
derives from type B
.
- When
A
uses a value of type B
as part of a function signature.
- When
A
uses B
in its implementation.
- I probably forget something here (I recall there were more reason why classes would be coupled).
When you have a cyclic dependency between two classes, there may be ways to break this dependency. Often, the dependency can be broken by splitting one of the two classes into a base class and a derived class with the base class not depending on the other class. There are a number of other approaches to break dependency cycles. John Lakos's "Large Scale C++" (1996) is essentially all about break dependency cycles and motivating why cyclic dependencies are bad (I guess, he would disagree with this simplifying characterization).
... and, yes, cyclic dependencies are bad:
- They cause programs to include unnecessary functionality because things are dragged in which aren't needed.
- They make it a lot harder to test software.
- They make it a lot harder to reason about software.
- They make it a lot harder to replace parts of the system.
- ... and probably a number of other reasons.
The above is formulated with a view taken from a C++ perspective. Some of the causes of circular dependencies may not exist [directly] in C but the same concepts roughly apply to C, too.