|
|
Another way to control usage dependency is to minimize the number of type conversion operators. Suppose that a component X defines class A, and that class A defines conversions among itself and three other other classes B, C, and D, contained in three other components. Then the header file for component X must include the header files for the other three components. Again, this causes excessive compile times for any client that includes X.h. A concrete example may help make this clear.
Among the container classes, for example, there are several conversions that might be considered useful. A conversion from List to Set, for example, would be useful to clients who don't care about duplicate elements or element ordering. We might have defined such a conversion as follows:
List.h // The following introduces a usage dependency // (List now depends on Set) #include <Set.h> template <class T> class List { public: operator Set<T>(); ... }
However, as the comment notes, the inclusion of Set.h introduces a dependency. Consequently, we do not provide the conversion. If the client wants such a conversion, the client must provide it, and must pay for the extra compilation time. Fortunately, iterators make such conversions easy to write:
client.c #include <List.h> #include <Set.h>
void List_to_set(const List<int>& l, Set<int>& result) { result.remove_all(); Listiter<int> li(l); const int* p; while (p = li.next()) result.insert(*p); }