Good practice is to not worry about your header strategy as long as it compiles.
The header section of your code is just a block of lines that nobody should even look at until you get an easily resolved compile error. I understand the desire for 'correct' style, but neither way can really be described as correct. Including a header for every class is more likely to cause annoying order-based compile errors, but those compile errors also reflect problems that careful coding could fix (though arguably they're not worth the time to fix).
And yes, you will have those order-based problems once you start getting into friend
land.
You can think of the problem in two cases.
Case 1: You have a small number of classes interacting with each other, say less than a dozen. You regularly add to, remove from, and otherwise modify these headers, in ways that may affect their dependencies on each other. This is the case which your code example suggests.
The set of headers is small enough that it is not complicated to solve any problems that crop up. Any difficult problems are fixed by rewriting one or two headers. Worrying about your header strategy is solving problems which do not exist.
Case 2: You have dozens of classes. Some of the classes represent the backbone of your program, and rewriting their headers would force you to rewrite/recompile a great amount of your code base. Other classes use this backbone to accomplish things. This represents a typical business setting. Headers are spread across directories and you can't realistically remember the names of everything.
Solution: At this point, you need to think of your classes in logical groups and collect those groups into headers which stop you from having to #include
over and over. Not only does this make life simpler, it is also a necessary step to taking advantage of precompiled headers.
You end up #include
ing classes you don't need but who cares?
In this case, your code would look like...
#include <Graphics.hpp>
struct Entity {
Texture texture;
RenderObject render();
}
#ifndef _RENDER_H #define _RENDER_H ... #endif
.#pragma once
settles it, no?