2

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 declaration
    • MainClass free functions declarations
    • MainClass specialization declaration
    • MainClass specialization free function declarations
    • AuxiliaryClass1 declaration
    • AuxiliaryClass1 free functions declarations
    • AuxiliaryClassN declaration
    • AuxiliaryClassN free functions declarations

    • MainClass definition
    • MainClass free functions definitions
    • MainClass specialization definition
    • MainClass specialization free function definition
    • AuxiliaryClass1 definition
    • AuxiliaryClass1 free functions definitions
    • AuxiliaryClassN definition
    • AuxiliaryClassN free functions definitions

Where:

  • AuxiliaryClassK is a class logically or structurally related to MainClass (e.g. an iterator for MainClass, a nested class within MainClass, a derived class of MainClass 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 a impl 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).
  • 3
    Split your code to one hpp and one cpp per class, but before that, get yourself a copy of "Large Scale C++ Software Design" (amazon.com/Large-Scale-Software-Design-John-Lakos/dp/0201633620/… ) and make yourself through at least the first half of that book. – Doc Brown Apr 19 '14 at 11:32
  • @DocBrown Regarding the book you recommended. I have started reading it, however it seems outdated to me. For instance he talks about templates like they are not yet (efficiently) implemented by compilers (and my code is almost fully templated), he advocates about external redundant include guard but today’s compilers are smart and maintain a table of headers with include guards and don’t need to reopen them if there were already included. – bolov Apr 21 '14 at 11:25
  • 1
    Yes, some details are indeed outdated, nethertheless the book is IMHO still extremely helpful and worth reading for planning how to split headers and other source files. And I don't know any newer book which is more up-to-date and deals with physical C++ source code layout - if you find one, please let me know. – Doc Brown Apr 22 '14 at 17:59
1

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).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.