I am writing a static library for C/C++ (personal project). As my headers became rather large, I thought that splitting my headers would be a good idea.
Right now a header looks like this:
-
MainClass.hpp:
- namespace impl: implementation details enclosed in a namespace
impl
- forward declarations of classes declared below (when needed)
MainClass
declarationMainClass
free functions declarationsMainClass
specialization declarationMainClass
specialization free function declarationsAuxiliaryClass1
declarationAuxiliaryClass1
free functions declarations- …
AuxiliaryClassN
declarationAuxiliaryClassN
free functions declarationsMainClass
definitionMainClass
free functions definitionsMainClass
specialization definitionMainClass
specialization free function definitionAuxiliaryClass1
definitionAuxiliaryClass1
free functions definitions- …
AuxiliaryClassN
definitionAuxiliaryClassN
free functions definitions
- namespace impl: implementation details enclosed in a namespace
Where:
AuxiliaryClassK
is a class logically or structurally related toMainClass
(e.g. an iterator forMainClass
, a nested class withinMainClass
, a derived class ofMainClass
etc.)ClassX
free functions as recommended in How Non-Member Functions Improve Encapsulation and Monoliths "Unstrung"- definitions are in header because they are templates.
This is becoming very crowded and difficult for me to navigate so I thought that splitting across multiple headers would help. However I do not know how to do it right.
Here is how I think the structure could look like:
-
MainClass.hpp:
- forward declarations (when needed)
- small classes/structs definitions & declarations
#include
the other headers
-
_Class.hpp:
_Class
declaration_Class
free functions declarations
- _Class.inl:
_Class
definition_Class
free functions definitions
With a _Class
for each: MainClass
, MainClass
specialization, AuxiliaryClassK
.
My questions are:
- Is it reasonable to want to split a header (all are functionalities of
MainClass
) (I have headers over 1000 lines long and I foresee even longer ones) or should I leave it as it is? - Is the above split scheme ok? Should I further split a class and the free functions related to that class? Are there other solutions to make the code more maintainable?
- How to hide the other headers (not in a sense of obfuscating / making the code unavailable, but avoid exposing the headers the users see (e.g. in a GUI with autocomplete)? They should include and be aware only of
MainClass.hpp
. Seeing other headers without being clear that they are behind–the–scenes headers will produce unnecessary confusion. One idea is to add a prefix like an_
(underscore) or to put them in aimpl
folder. (Again, this is not about hiding classes (I do that with a namespace), but to hide the split behind a header they should use).
Best Answer
You can do the following:
split the code into one class per header file.
in the case of templates, the implementation of the class functions can/should reside in the same header file (there is probably no scenario when you will want include the header, but not those definitions).
dependencies (your
AuxiliaryClassK
) should be#included
instead of being defined directly. This makes your headers smaller, promotes code reuse (as you can include them - and only them - elsewhere) and keeps your code cleaner.split your code into directories. The directory structure is normally a matter of policy; You could use your impl folder idea, or (for example) you could group them like boost does (one directory per functional area with all the implementation files, and one include file for convenience, which you can include in a single line in client code).
use pimpl idiom to minimize compile times.
As a rule, I would not use _Class file names. They are unusual (you increase the WTF/LOC measurement of your code which is never good).