“It depends”. 
First, I’d say that compilation times should be the least of your worries, even if your build is quite slow, and you should be working on those things that make your code more reliable and easier for you to understand first. From seeing other people trying to optimize builds, changes like “separate files” don’t result in earth-shattering changes to build times one way or the other - i.e. “you almost certainly wouldn’t notice”.
There is a way to keep compile times down, or at least prevent them from ballooning, and that involves strong separation of .h files by using forward references.
I think an example from my codebase will speak loudly here. Instance is my “god class” that lets you get to everything in my application. I fought having one for a long time, but the mess always piled up somewhere else so I went the other way and made it a struct![code]#include “rec/base/base.h” // Tiny include file everyone has to have.
class Components;
class Menus;
class Model;
class Target;
class Threads;
class Listeners;
struct Instance {
explicit Instance(DocumentWindow* window);
~Instance();
DocumentWindow* window_;
ptr components_; // ptr<> is very much like ScopedPtr.
ptr device_;
ptr player_;
ptr model_;
ptr menus_;
ptr target_;
ptr listeners_;
ptr threads_;
DISALLOW_COPY_ASSIGN_AND_EMPTY(Instance);
};[/code]Note how all the classes that actually do the work are forward-references and so file doesn’t include any other file except my “base.h”.
This means it’s extremely “light” to include this file Instance.h file because it doesn’t pull in other things. If you specifically need to know how some of these classes work, then you as the client of Instance will have to include their include files, but in fact nearly all the clients just use one or two of the parts. Only Instance.cpp needs to include the actual declaration for each of its component parts!
I tend to go further and completely hide the very existence of some classes from everyone else! For example, I have a class that runs a callback in a thread - except that I expose it to no one:[code]// MakeThread.h: you only get a function declaration here, very light!
// Create a thread that runs a Callback.
Thread* makeThread(const String& name, Callback* cb);
// MakeThread.cpp is the only place you can find the actual class definition.
namespace {
class CallbackThread : public juce::Thread {
public:
CallbackThread(const String& name, Callback* cb) { /* … */ }
// …
};
} // namespace
Thread* makeThread(const String& name, Callback* cb) { return new CallbackThread(name, cb); }[/code]
It isn’t just that you’ll cut compilation times a reasonable amount; and it isn’t just that your code is compartmentalized so that build errors affect a lot less of the code base (making them much easier to track down); it’s that your code is compartmentalized so that you the programmer can simply forget about the very existence of certain classes that you wrote and are finished because you simply never see them - it simply lessens the cognitive burden on you, the programmer.