【问题标题】:Coding best practices编码最佳实践
【发布时间】:2014-02-26 01:27:37
【问题描述】:

在头文件中包含#include 语句是一种好的编程习惯吗?我个人认为,尤其是当您浏览其他人编写的代码库时,您最终会丢失或花时间寻找如果它在 c 文件中本可以更快找到的定义。

【问题讨论】:

  • 经验法则,永远不要包含您不需要的任何东西。头文件通常具有较少的依赖关系,并且可以通过使用前向声明来减少包含。
  • 头文件是接口,所以通常#include在.c
  • 在实践中,您经常需要在标题中包含其他文件。但是,它应该是尽可能少的包含集,但不要听任何人就包含/不包含标题做出笼统的陈述。实践与理论背道而驰。

标签: c++ c


【解决方案1】:

在某些情况下(根据我的经验 - 大多数),按照你说的去做是不可能的。您通常最终会从代​​码中返回各种其他类,并且 - 显然 - 您需要在函数声明中包含有关这些类的信息。在这种情况下,编译器必须已经知道那些其他对象是什么,因此您必须已经在声明中包含一个标头,或者提供一个前向声明。

由于无论如何您最终都会包含标题,因此进行额外的前向声明没有真正意义。这当然是一个选择,但在我看来它并没有让你的代码更清晰。

另外 - 大多数 IDE 都可以选择在包含的文件中查找符号。

如果(并且只有如果)您在定义中只需要类/函数,那么您可以投票将标题包含在*.c 文件中。乍一看可能很清楚,但您可能会发现 - 当有一天修改类时 - 无论如何,您最终都会将 #include 移动到 *.h 文件中。

【讨论】:

    【解决方案2】:

    简短的回答是肯定的。如果一个特定的头文件定义/声明了由其他头文件中定义/声明的类、类型、结构等组成的类、类型、结构等,那么最方便和有效的做法是包含这些头文件文件放入头文件中。

    通过这样做,依赖于您正在创建的头文件的头文件将在那里。

    可能存在文件被多次包含的问题,这就是为什么大多数头文件包含 #if 以确保文件仅包含一次或使用 #pragma 之类的内容以确保仅包含一次。

    总而言之,您应该设计您的头文件,以便如果通过多次使用头文件的#include 多次包含它们,则该头文件只会在预处理器输出中出现一次。通过在头文件中包含头文件所依赖的头文件,您可以本地化头文件的使用并确保任何依赖项都可用。

    另外通过在你的头文件中使用依赖头文件的#include,如果包含路径不正确导致依赖头文件不可用,很容易找到依赖于不可用的头文件头文件。

    【讨论】:

    • 这是有道理的。我在 C 中编码的经验非常少,并且想知道如果将来有人修改它包含一个已经包含在一个头文件中的头文件会发生什么。我找不到任何关于此的信息,但我可以看到我们如何使用预处理器语句确保它不会发生。
    • @arTsmarT:这就是你使用包含守卫的原因
    【解决方案3】:

    头文件应该管理它们自己的依赖;必须在 .c 文件中获得#includes 的顺序刚刚正确是浪费一个下午的烦人方式,而且这将是一个永久的维护头痛。 #include 是否有您直接需要的标头,在您自己的标头中使用 #include 守卫,生活会轻松得多

    【讨论】:

      【解决方案4】:

      如果有必要使头文件自包含,因为它不依赖于任何其他手动包含的头文件,那么它的风格也不错。例如,如果标头包含使用来自stdint.h 的数据类型的声明,那么它应该有#include <stdint.h>,而不是期望每个人都以正确的顺序单独包含它。

      同时,不必要的#includes 通常风格不佳,无论它们在哪里(.h.c)。可以说,一个例外可能是整个库集合,理论上可以单独使用,但打算作为一个整体使用,例如完整的 GUI 工具包——在这种情况下,我认为拥有一些拉动的主标头会更干净在所有声明中,而不是让用户了解哪个特定功能需要哪个标头。

      【讨论】:

        【解决方案5】:

        我宁愿在头文件中没有#include,如果只是为了让每个源文件的依赖项在一个地方可见。但这当然是有争议的。

        黄金法则是可读性。白银规则是遵循现有做法

        【讨论】:

          【解决方案6】:

          不要#include任何你不需要的东西。

          不要#include 任何您不需要的东西,因为包含不必要的文件会导致不必要的依赖关系,并且还会导致大型项目的编译时间更长。因此,如果您修改了现有类以将 vector 替换为 list,请多花几秒钟时间查看文件并确保没有留下任何 vector 残留物,然后删除 @ 987654326@ 从文件顶部开始。

          尽可能使用前向声明而不是#include

          尽可能使用前向声明,因为它可以减少依赖关系并最大限度地减少编译时间。如果您的类头没有声明该类的对象,则可以使用前向声明;如果您仅通过指针或(在 C++ 中)通过引用使用它,那么您可以通过前向声明来解决。

          使用#ifdef#pragma 保护设计您的头文件,使其不会被多次包含。

          // MyClass.h
          
          #ifndef MYCLASS_HEADER
          #define MYCLASS_HEADER
          
          // [header declaration]
          
          #endif // MYCLASS_HEADER
          

          或者在 Visual Studio 等支持编译器上:

          // MyClass.h
          
          #pragma once
          
          // [header declaration]
          

          这些守卫将允许您根据需要随时#include "MyClass.h",而不必担心将其多次包含在同一个翻译单元中。

          如果头文件需要包含的文件,则在头文件中包含/转发声明。

          如果标头需要前向声明或完全包含标头,那么这样做很容易。

          如果头文件不需要包含的文件,但实现需要,则包含在 .c/.cpp 文件中。

          如果标头对标头没有用——因为前向声明就足够了,或者因为只有 .c/.cpp 文件需要它——那么不要在标头中使用#include。请记住:尽可能将任何内容推送到 .c/.cpp 文件中,以减少依赖关系并最小化编译时间。

          【讨论】:

            猜你喜欢
            • 2014-07-31
            • 1970-01-01
            • 2012-02-24
            • 1970-01-01
            • 1970-01-01
            • 2014-04-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多