开发者

Any good reason for C++ header file to not include any other header files?

开发者 https://www.devze.com 2023-03-26 05:43 出处:网络
I\'ve seen a header include style like this, where header files don\'t include other header files and the corresponding *.cpp files must include all the dependencies (and include them in the right ord

I've seen a header include style like this, where header files don't include other header files and the corresponding *.cpp files must include all the dependencies (and include them in the right order). It seems possible that in the good old days that this would make build dependency tracking easier (but I'm just guessing). Is there a good reas开发者_Python百科on for it nowadays?

File "B.h":

#ifndef _B_h_
#define _B_h_

// Note we do not #include "A.h" that contains class A declaration.

class B
{
public:
   A a; // An A object.
};
#endif // _B_h_

File "B.cpp":

#include "A.h" // Must include this before B.h, otherwise class A not defined in B.h
#include "B.h"

...


Yeah, that would be bad practice, because if somebody gets the order wrong they'll get errors that they may or may not be able to figure out. If all the header files have include guards, then one header including all the other headers it needs won't be a problem, which is how it should be.


It seems whoever wrote that code misunderstood the common recommendation of reducing the number of included headers. It is usually recommended to remove unnecessary #include <> directives in the hope of accelerating compilation. Indeed, on large projects, it may accelerate compilation significantly by:

  1. reducing the number of header files the compiler needs to open to compile any given source file;
  2. reducing the number of source files that need to be recompiled after a header changes.

In general, people will recommend (its been on coding standards for all projects I've worked on) using forward declarations for classes unless the class defined in the concerned header is:

  1. used as a base class;
  2. used as a data member;
  3. has an incomplete official speciifcation (e.g. standard library containers are allowed to have extra template arguments as long as they have defaults, so it's non-standard to forward declare them).

In cases 1 and 2, the #include <> directive must appear before the class definition in all dependent source files and headers. Basically, it just moves the #include <> directive(s) from the header into each of its dependencies. It results in more code and does so with no benefit (e.g. compilation time etc. will be the same). For this reason, this recommendation is also accompanied by another entry in the coding standard: each header file should compile "stand alone" (e.g. included on the first line of a source file).


It's a really bad practice. Let the compiler figure out the right order- it's less error-prone. Headers should compile as if they were included on their own- i.e., if you had a TU consisting of just #include "B.h".


Is there a good reason for it nowadays?

No, not really. People do all kinds of stuff that "will work" either because they don't know any better, don't care or have more important things to worry about. It happens when your language relies on a preprocessor instead of having a real module-import system.

I would say it's best practice to ensure that the person #including your stuff never has to worry about the order of includes or hidden pre-requisites. Unless of course your hand is forced by some 3rd party's stupid macro tricks, anyway.


Yes, I would recommend #including' any dependency of the INTERFACE in any header.

In this case, yes: I would #include "A" (because B's interface depends on A).

Otherwise, if the implementation used "A" (but the header didn't), I would only #include A in the .cpp (because it's not part of the interface).

Under NO circumstances would I want the order of the headers to matter, if at all avoidable. Typically, the header order SHOULDN'T matter.

IMHO...

PS: As much as Bjarne Stroustrup wishes otherwise, the preprocessor and preprocessor macros are still very much with us. Certainly in C-land, and certainly in just about any Microsoft API. It's just good form to respect that fact.


I would consider this bad style. It will lead to tough to understand errors.

The reason you might do it would be to avoid recompiling a lot of code each time you made changes to a single header file. If you find yourself in this situation though, you probably have a design issue.

0

精彩评论

暂无评论...
验证码 换一张
取 消