|
|
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);
}