代码之家  ›  专栏  ›  技术社区  ›  David Mason

在“头文件”和“实现文件”(C++)中是否应该重复“包含”和“使用”语句?

  •  6
  • David Mason  · 技术社区  · 15 年前

    我对C++是相当新的,但是我的理解是,一个包含语句将基本上将包含的文件的内容转储到该语句的位置。这意味着,如果我的头文件中有多个“include”和“using”语句,那么我的实现文件只能“include”头文件,编译器不会介意我是否重复其他语句。

    但是人们呢?

    我主要担心的是,如果我不重复'include'、'using'和'typedef'(现在我已经想到了)语句,它会从使用它的文件中带走这些信息,这可能会导致混淆。

    我现在只是在做一些小项目,不会真正引起任何问题,但我可以想象,在有更多人参与的大项目中,这可能会成为一个重大问题。

    示例如下:

    更新: 我的“unit”函数原型的返回类型和参数中有string、ostream和stringset——我的头文件中没有只在实现文件中使用的任何内容。

    //Unit.h
    
    #include <string>
    #include <ostream>
    #include "StringSet.h"
    
    using std::string;
    using std::ostream;
    
    class Unit {
    
    public:
        //public members with string, ostream and StringSet
        //in their return values/parameter lists
    private:
        //private members
        //unrelated side-question: should private members
        //even be included in the header file?
    } ;
    
    
    //Unit.cpp
    
    #include "Unit.h"
    
    //The following are all redundant from a compiler perspective:
    #include <string>
    #include <ostream>
    #include "StringSet.h"
    
    using std::string;
    using std::ostream;
    
    //implementation goes here
    
    5 回复  |  直到 8 年前
        1
  •  6
  •   Travis Gockel    8 年前

    使用指令 ( using namespace std; )不应驻留在头中,除非它包含在函数中。这是不好的做法。头的每个用户都不太可能希望对给定命名空间中的所有内容进行无保留的查找;包含不相关的头可能会导致意外的歧义和编译失败。就我个人而言,我避免 使用指令 在函数内部进行同样的推理,但这通常被认为危害较小。

    类型别名 (要么通过 typedef std::string string; using string = std::string; )应该小心使用。类型定义有意义,因此不应重新声明它。例如,这是一个错误:

    typedef int   myint;
    typedef float myint;
    

    因为类型冲突。

    使用声明 ( using std::string; using std::memcpy; )使符号可用于 unqualified name lookup . 这是非常有用的,当得到 argument-dependent lookup 对,除非你在写一个图书馆,否则这通常无关紧要。建议是不同的,这取决于您是否要引入类型或函数。想想 使用声明 s的类型与 类型别名 :在同一名称下有多个定义是没有意义的。对于函数,您真正要做的就是扩展重载解析以包含更多内容(尽管通常不需要)。

    // Finding multiple operator<< functions makes sense
    using std::operator<<;
    using mylib::operator<<;
    
    // Finding multiple string classes does not make sense
    using std::string;
    using mylib::string;
    

    为了重复 #include ,您应该首先考虑是否需要将文件包含在头中。也许是 forward declaration 符合你的需要。

        2
  •  3
  •   paercebal    15 年前
    • 只在头/源中包含您真正需要的内容 (如果forward声明可用且足够,则forward声明而不是include)
    • 不要使用 using 标题中的语句 (除非在函数范围内)。添加 使用 在头中会污染包括头在内的所有源的名称空间。
    • 您应该确保每个文件(源文件的头)包含它所需的所有内容,而不是更多。

    你不需要关心是否有些内容是多余的。头部保护和预编译器优化可以帮您处理这个问题。

    您应该能够单独操作每个文件。

    例如,假设您使用 std::string 在头和源中,但是,作为“优化”,您只在头中包含字符串…如果以后发现不再需要头中的字符串,并希望将其删除(代码清理和所有…),则必须修改源以包含该字符串。现在,假设你有十个来源包括标题…

    现在,当然,您可以有这个规则的例外(例如,预编译头,甚至头woe唯一的目的是做多个包含作为一种礼貌),但在默认情况下,您应该有自给自足的头和源文件(即,文件包括他们使用的任何东西,不再少)。

        3
  •  0
  •   Nick    15 年前

    尽量减少头文件。这意味着尽可能少的包含。.cpp文件通常包括相应的头以及实现所需的任何其他头。

        4
  •  0
  •   Alex Korban    15 年前

    就像特拉维斯说的,你不应该 using 头文件中的语句,因为这意味着它们将包含在包含该头文件的所有翻译单元中,这可能会导致混淆问题。

    如果我只需要cpp文件的头文件中的功能,那么我只将其包含在该cpp文件中。对于大型项目来说,这是一个很好的实践,因为这意味着编译器的工作量会减少。此外,在可能的情况下,我在头文件中使用forward声明,而不是include(同样,在cpp文件中包含头文件)。

        5
  •  0
  •   Alan    15 年前

    有一个 using 语句,除非有意将符号复制到其他命名空间中。可以在cpp文件中使用。

    typedef 应该只在代码库中存在一次。如果需要在多个cpp/h文件中使用,则应该在头文件中。复制它们会让你很伤心。

    头文件应该包含 #include 它需要的陈述,而不是其他的。如果只提到指向类的指针,则使用forward声明,而不包括头。只有在cpp文件中才需要的任何其他包含都应该放在那里。从头部重复includes是可以的,但不是必需的。这只是一种风格的选择。

    推荐文章