Pros & Cons of putting all code in Header files in C++?
Solution 1:
Reason [1] Faster compile times
Not in my projects: source files (CPP) only include the headers (HPP) they need. So when I need to recompile only one CPP because of a tiny change, I have ten times the same number of files that are not recompiled.
Perhaps you should break down your project in more logical sources/headers: A modification in class A's implementation should NOT need the recompilation of implementations of class B, C, D, E, etc..
Reason[2] It avoids circular dependencies
Circular dependencies in code?
Sorry, but I have yet to have this kind of problem being a real problem: Let's say A depends on B, and B depends on A:
struct A
{
B * b ;
void doSomethingWithB() ;
} ;
struct B
{
A * a ;
void doSomethingWithA() ;
} ;
void A::doSomethingWithB() { /* etc. */ }
void B::doSomethingWithA() { /* etc. */ }
A good way to resolve the problem would be to break down this source into at least one source/header per class (in a way similar to the Java way, but with one source and one header per class):
// A.hpp
struct B ;
struct A
{
B * b ;
void doSomethingWithB() ;
} ;
.
// B.hpp
struct A ;
struct B
{
A * a ;
void doSomethingWithA() ;
} ;
.
// A.cpp
#include "A.hpp"
#include "B.hpp"
void A::doSomethingWithB() { /* etc. */ }
.
// B.cpp
#include "B.hpp"
#include "A.hpp"
void B::doSomethingWithA() { /* etc. */ }
Thus, no dependency problem, and still fast compile times.
Did I miss something?
When working on "real-world" projects
in a real-world project, cpp files tend to include random headers until you can't figure out who depends on whom
Of course. But then if you have time to reorganize those files to build your "one CPP" solution, then you have time to clean those headers. My rules for headers are:
- break down header to make them as modular as possible
- Never include headers you don't need
- If you need a symbol, forward-declare it
- only if the above failed, include the header
Anyway, all headers must be self-sufficient, which means:
- An header include all needed headers (and only needed headers - see above)
- an empty CPP file including one header must compile without needing to include anything else
This will remove ordering problems and circular dependencies.
Is compile times an issue? Then...
Should compile time be really an issue, I would consider either:
- Using precompiled headers (this is quite useful for STL and BOOST)
- Decrease coupling through the PImpl idiom, as explained in http://en.wikipedia.org/wiki/Opaque_pointer
- Use network shared compilation
Conclusion
What you are doing is not putting everything in headers.
You are basically including all your files into one and only one final source.
Perhaps you are winning in terms of full-project compilation.
But when compiling for one small change, you'll always lose.
When coding, I know I compile often small changes (if only to have the compiler validate my code), and then one final time, do a full project change.
I would lose a lot of time if my project was organized your way.
Solution 2:
I disagree with point 1.
Yes, there is only one .cpp and the built time from scratch is faster. But, you rarely build from scratch. You make small changes, and it would need to recompile the whole project each time.
I prefer doing it the other way around:
- keep shared declarations in .h files
- keep definition for classes that are only used in one place in .cpp files
So, some of my .cpp files start looking like Java or C# code ;)
But, 'keeping stuff in .h' approach is good while designing the system, because of point 2. you made. I usually do that while I'm building the class hierarchy and later when code architecture becomes stable, I move code to .cpp files.
Solution 3:
You are right to say that your solution works. It may even have no cons for your current project and developing environment.
But...
As others stated, putting all your code in header files forces a full compilation every time you change one line of code. This may not be an issue yet but your project may grow large enough to the point compilation time will be an issue.
Another problem is when sharing code. While you may not be directly concerned yet, it is important to keep as much code as possible hidden from a potential user of your code. By putting your code into the header file, any programmer using your code must look the whole code, while there are just interested in how to use it. Putting your code in the cpp file allows to only deliver a binary component (a static or dynamic library) and its interface as header files, which may be simpler in some environment.
This is a problem if you want to be able to turn your current code into a dynamic library. Because you don't have a proper interface declaration decoupled from the actual code, you won't be able to deliver a compiled dynamic library and its usage interface as readable header files.
You may not have these issues yet, that's why I was telling that your solution may be ok in your current environment. But it is always better to be prepared to any change and some of these issues should be addressed.
PS: About C# or Java, you should keep in mind that these languages are not doing what you say. They are actually compiling files independently (like cpp files) and stores the interface globally for each file. These interfaces (and any other linked interfaces) are then used to link the whole project, that's why they are able to handle circular references. Because C++ does only one compilation pass per file, it is not able to globally store interfaces. That's why you are required to write them explicitely in header files.