Crowded with thousands of lines of code?
Having one set of headers / source files for each class in a directory might seem redundant. And if the number of classes goes to 100 or 1000, it can even get scared.
But, playing with the sources, following the philosophy of “let's all together”, the conclusion is that only the one who wrote the file has some hope not to get lost inside. Even when working with the IDE, it’s easy to miss something, because when you play with a source of 20,000 lines, you simply close your mind to something that does not fit your problem.
Real life example: the class hierarchy defined in these thousands of sources has closed itself into diamond inheritance, and some methods have been redefined in child classes by methods with exactly the same code. This was easily missed (who wants to study / check 20,000 lines of source code?), And when the original method was changed (bug fixed), the effect was not as universal as the exception.
Dependencies getting round?
I had this problem with a code template, but I saw similar problems with regular C ++ and C code.
Destruction of sources in 1 heading for each structure / class allows you to:
- Speed up compilation because you can use the forward-declaration character instead of including whole objects.
- Have circular dependencies between classes (§) (i.e. class A has a pointer to B, and B has a pointer to A)
In source-controlled code, class dependencies can cause classes to move up and down the file regularly, just to compile the header. You do not want to study the evolution of such movements when comparing the same file in different versions.
The presence of separate headers makes the code more modular, compiles faster and simplifies the study of its evolution using different versions of diffs
For my template program, I had to split the headers into two files: the .HPP file containing the declaration / definition of the template class, and the .INL file containing the definitions of the mentioned class methods.
Putting all this code inside one and only one unique header would mean including class definitions at the beginning of this file and a method definition at the end.
And then, if someone needs only a small part of the code, with a solution for only one header, they will still have to pay for a slower compilation.
(§) Note that you can have circular dependencies between classes if you know which class belongs to them. This is a discussion about classes that have knowledge about the existence of other classes, rather than round-robin circular dependencies shared_ptr.
Last word: headlines should be self-sufficient
One thing, however, must be respected by the decision of several headings and several sources.
When you include one header, no matter what the header, your source should compile cleanly.
Each title should be self-sufficient. You should develop the code, and not search for treasures, burn your project with more than 100,000 source files to determine which heading defines the character in the heading of 1000 lines, which you only need to include for just one listing.
This means that either each header defines, or forward-declare all the characters it uses, or includes all the necessary headers (and only the necessary headers).
Circular dependency issue
underscore-d asks:
Can you explain how using separate headers has any meaning for circular dependencies? I do not think so. We can trivially create a circular dependency, even if both classes are fully declared in the same header, just by forward declaration well in advance before declaring a handle to it in the other. Everything else seems to be great points, but the idea that individual headings facilitate circular dependencies seems empty.
underscore_d, November 13 at 11:20 p.m.
Say you have 2 class templates, A and B.
Say a class definition A (respectively B) has a pointer to B (respectively A). Let also methods of class A (respectively, B) actually call methods from B (respectively, A).
You have a cyclical dependency both in the definition of classes and in the implementation of their methods.
If A and B were normal classes, and methods A and B were in .CPP files, there would be no problem: you would use the forward declaration, have a header for each class definition, then each CPP would include as HPP.
But since you have the templates, you really need to reproduce these templates above, but only with the headers.
It means:
- definition header A.def.hpp and B.def.hpp
- implementation header A.inl.hpp and B.inl.hpp
- for convenience, the “naive” headline of A.hpp and B.hpp
Each heading will have the following attributes:
- In A.def.hpp (e.g. B.def.hpp) you have a direct declaration of class B (respectively A) that allows you to declare a pointer / link to this class
- A.inl.hpp (e.g. B.inl.hpp) will include both A.def.hpp and B.def.hpp, which will allow methods from A (respectively B) to use class B (respectively A).
- A.hpp (respectively B.hpp) will directly include both A.def.hpp and A.inl.hpp (respectively B.def.hpp and B.inl.hpp)
- Of course, all headings should be self-contained and protected by heading defenders.
A naive user will include A.hpp and / or B.hpp, while ignoring the entire mess.
And the presence of this organization means that the librarian can resolve circular dependencies between A and B, saving both classes in separate files, it is easy to move around as soon as you understand the scheme.
Note that this was a boundary register (two patterns that know each other). I expect most code will not need this trick.