Search code examples
c++includeinclude-guards

Only include headers in interface, not in implementation


My header files look like:

// A.hpp --- A's interface

#ifndef MY_H
#define MY_H

#include<string>
#include<vector>

class A {
 public:
  A(const std::string& name);
  std::vector<double> foo() const;
 private:
  std::string m_name;
};

#endif

And my implementation files look like:

// A.cpp --- A's interface implementation
#include<A.hpp>

#include<implementation_detail.hpp>

A::A(const std::string& name)
 : m_name(name) { }

std::vector<double> A::foo() const {
 std::vector<double> r;
 r.push_back(1);
 return r;
}

My stand is that I do not #include string or vector in the implementation file because they are already declared in the interface, and #includeing them in the implementation file is superfluous at best, and detrimental at worse**.

Of course, A's implementation will #include all implementation details not visible from the interface.

My questions: Am I correct? Can this practice affect my code negatively?

** It is far-fetched, but the number of includes (and the include guards used) can have an effect in compilation speed for very large projects; this article is interesting.


Solution

  • It's a matter of style and personal preference.

    For header files, my personal preference is to make the header file stand on its own, but just barely. By "stand on its own" I mean that I should be able to #include that header in some random source file and that source file will still compile.

    #include "some_random_header_file.h"
    int main () {}
    

    The above should always compile. By "just barely", I mean that the header should be free of gratuitous #include directives. If some #include does not provide functionality used directly in a header file, I don't #include that other header in the header file.

    For source files, my personal preference is to #include every header that provides functionality used in the source file. If the code a source file calls std::string::append, that source file had better #include <string> -- even if some other header has already included it.