c++ - 将所有代码放在 C++ 头文件中的优点和缺点?

标签 c++ architecture compilation header-files circular-dependency

您可以构造一个 C++ 程序,以便(几乎)所有代码都驻留在头文件中。它本质上看起来像一个 C# 或 Java 程序。但是,您确实需要至少一个 .cpp 文件来在编译时拉入所有头文件。现在我知道有些人绝对会讨厌这个想法。但我没有发现这样做有任何令人信服的缺点。我可以列出一些优点:

[1] 更快的编译时间。所有头文件只被解析一次,因为只有一个 .cpp 文件。此外,一个头文件不能包含多次,否则会导致构建中断。使用替代方法时,还有其他方法可以实现更快的编译,但这很简单。

[2] 它通过使它们绝对清晰来避免循环依赖。如果 ClassA.h 中的 ClassAClassB.h 中的 ClassB 有循环依赖,我必须放一个前向引用&它突出。 (请注意,这与编译器自动解析循环依赖关系的 C# 和 Java 不同。这鼓励了 IMO 的不良编码实践)。同样,如果您的代码位于 .cpp 文件中,您可以避免循环依赖,但在实际项目中,.cpp 文件往往会包含随机 header ,直到您可以'不知道谁依赖谁。

你的想法?

最佳答案

原因 [1] 更快的编译时间

不在我的项目中:源文件 (CPP) 仅包含他们需要的 header (HPP)。所以当我因为一个微小的变化而只需要重新编译一个 CPP 时,我有十倍于相同数量的未重新编译的文件。

也许您应该将项目分解为更合乎逻辑的源/标题:A 类实现的修改不需要重新编译 B、C、D、E 等类的实现。

原因[2] 避免循环依赖

代码中的循环依赖?

抱歉,我还没有遇到真正的问题:假设 A 依赖于 B,B 依赖于 A:

struct A
{
   B * b ;
   void doSomethingWithB() ;
} ;

struct B
{
   A * a ;
   void doSomethingWithA() ;
} ;

void A::doSomethingWithB() { /* etc. */ }
void B::doSomethingWithA() { /* etc. */ }

解决问题的一个好方法是将此源分解为每个类至少一个源/ header (以类似于 Java 的方式,但每个类有一个源和一个 header ):

// 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. */ }

因此,没有依赖性问题,并且编译时间仍然很快。

我错过了什么吗?

在从事“现实世界”项目时

in a real-world project, cpp files tend to include random headers until you can't figure out who depends on whom

当然。但是,如果您有时间重新组织这些文件以构建您的“一个 CPP”解决方案,那么您就有时间清理这些 header 。我的标题规则是:

  • 分解标题以使其尽可能模块化
  • 永远不要包含你不需要的标题
  • 如果你需要一个符号,前向声明它
  • 仅当上述失败时,才包含标题

无论如何,所有的 header 必须是自给自足的,这意味着:

  • 一个 header 包括所有需要的 header (并且只有需要的 header - 见上文)
  • 必须编译包含一个 header 的空 CPP 文件,而无需包含其他任何内容

这将消除排序问题和循环依赖。

编译时间有问题吗?那么……

如果编译时间真的是一个问题,我会考虑:

结论

您所做的并不是将所有内容都放在标题中。

您基本上是将所有文件包含在一个且只有一个最终源中。

也许您在完整项目编译方面获胜。

但是当编译一个小的改变时,你总是会输的。

编码时,我知道我经常编译小的更改(如果只是让编译器验证我的代码),然后最后一次,做一个完整的项目更改。

如果我的项目按照你的方式组织,我会浪费很多时间。

关于c++ - 将所有代码放在 C++ 头文件中的优点和缺点?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/193864/

相关文章:

c++ - 带有自定义比较器的优先级队列

c++ - 将 C++ 对象传递给 ChaiScript 函数

swift - FireBase - 将子项(按原样)移动到不同的路径

java - 如何根据需求或功能设计类

嵌入到 .bat 文件中的 C# 源代码

c - C 编译器将 "-DFOO"处理为与 "-DFOO=1"相同的事实上的标准吗?

c++ - GMP 随机 float 生成

mysql - 处理随机 ID 存储

compiler-errors - 如何修复Flex代码生成器上的 'unrecognized rule'和 'Fatal parse '错误?

c++ - 关于 vector 值