Я считаю, что, если вы не используете предварительно скомпилированные заголовки MSVC и не используете Makefile или другую систему сборки на основе зависимостей, отдельные исходные файлы должны компилироваться быстрее при итеративной сборке. Поскольку моя разработка почти всегда итеративна, меня больше волнует, насколько быстро она может перекомпилировать изменения, которые я сделал в файле x.cpp, чем в двадцати других исходных файлах, которые я не изменил. Кроме того, я делаю изменения намного чаще в исходных файлах, чем в API, поэтому они изменяются реже.
Что касается круговых зависимостей. Я бы посоветовался с Парсебалом на шаг дальше. У него было два класса, которые имели указатели друг на друга. Вместо этого я чаще сталкиваюсь с ситуацией, когда один класс требует другого класса. Когда это происходит, я включаю заголовочный файл для зависимости в заголовочный файл другого класса. Пример:
// foo.hpp
#ifndef __FOO_HPP__
#define __FOO_HPP__
struct foo
{
int data ;
} ;
#endif // __FOO_HPP__
.
// bar.hpp
#ifndef __BAR_HPP__
#define __BAR_HPP__
#include "foo.hpp"
struct bar
{
foo f ;
void doSomethingWithFoo() ;
} ;
#endif // __BAR_HPP__
.
// bar.cpp
#include "bar.hpp"
void bar::doSomethingWithFoo()
{
// Initialize f
f.data = 0;
// etc.
}
Причина, по которой я включил это, что немного не связано с циклическими зависимостями, заключается в том, что я чувствую, что есть альтернативы включению заголовочных файлов в произвольном порядке. В этом примере исходный файл struct bar не включает заголовочный файл struct foo. Это делается в заголовочном файле. Это имеет преимущество в том, что разработчику, использующему панель, не нужно знать о каких-либо других файлах, которые разработчик должен будет включить, чтобы использовать этот заголовочный файл.