[ fromfile: classdeclarations.xml id: classdeclarations ]
Bidirectional relationships not very different from Figure 2.4 appear quite often in classes.
To implement them,
the compiler needs to have some knowledge of each class before defining the other.
At first, you might think that each header file should #include
the other, as shown in Example 2.12.
Example 2.12. src/circular/badegg/egg.h
[ . . . . ] #include "chicken.h" class Egg { public: Chicken* getParent(); }; [ . . . . ]
<include src="src/circular/badegg/egg.h" href="src/circular/badegg/egg.h" id="badeggh" mode="cpp"/>
The problem becomes clear when you look at Example 2.13, which analogously includes egg.h
.
Example 2.13. src/circular/badegg/chicken.h
[ . . . . ] #include "egg.h" class Chicken { public: Egg* layEgg(); }; [ . . . . ]
<include src="src/circular/badegg/chicken.h" href="src/circular/badegg/chicken.h" id="badchickenh" mode="cpp"/>
The preprocessor does not permit circular dependencies such as these. In this example, neither header file needed to include the other. In each case, doing so created an unnecessarily strong dependency between header files.
Under the right conditions, C++ permits you to use a forward class declaration instead of #including
a particular header.
Example 2.14. src/circular/goodegg/egg.h
A forward class declaration enables you to refer to a symbol without having its full definition available.
It is an implicit promise to the compiler that the definition of the class will be #included
when it is needed.
Classes that are declared but not defined can only be used as types for pointers or references, as long as they are not dereferenced in the file.
We define getParent()
in the source code module, egg.cpp
, shown in Example 2.15.
Notice that the .cpp
file can #include
both header files without causing a circular dependency between them.
The .cpp
file has a strong dependency on both headers, while the header files have no dependency on one another.
Example 2.15. src/circular/goodegg/egg.cpp
Thus, forward class declarations make it possible to define bidirectional relationships, such as the one above without creating circular #include
s. We located the dependencies in the source code modules that actually needed them instead of in the header files.
In Java, you can create circular strong bidirectional dependencies between two (or more) classes. In other words, each class can import
and use (dereference references to) the other. This kind of circular dependency makes both classes much more difficult to maintain because changes in either one can break the other. This is one situation where C++ protects the programmer better than Java does: You cannot create such a relationship accidentally.
Java also offers a forward class declaration, but it is rarely used because Java programs do not use separate header and implementation files.
For further details, see Section C.2
Generated: 2012-03-02 | © 2012 Alan Ezust and Paul Ezust. |