使用C ++头文件的最佳实践

时间:2009-01-04 05:38:37

标签: c++ header-files

我对头文件的使用有以下疑问。

1 - 在评论后加入警卫

/* Copyright Note and licence information (multiple lines) */
#ifndef FOO_H
#define FOO_H
// Header file contents
#endif

Herb Sutter在他的“C ++编码标准”一书中说,像上面这样的代码是有问题的。他说“#ifndef”语句应该出现在头文件的第一行。我觉得这并不令人信服。在头文件中你跟着你们/ gals吗?

2 - 在头文件中使用名称空间

#ifndef FOO_H
#define FOO_H
namespace FooNameSpace{
    // Header file contents
}
#endif

以上代码是否使用了正确的做法?我的意思是,你在头文件中使用命名空间吗?我知道为什么在头文件中导入名称空间是没有意义的,但是如上所述的声明呢?

如果上面的方法是正确的,那么如何对另一个名称空间中的类进行“转发声明”?是吗

#ifndef FOO_H
#define FOO_H
namespace AnotherNameSpace{
    class AnotherFoo; // forward declaration
}

namespace FooNameSpace{
    // Use AnotherFoo here
}
#endif

转发声明”是避免“循环依赖”的唯一方法,对吗?

5 个答案:

答案 0 :(得分:18)

  1. 包含守卫和评论的顺序纯粹是一种风格问题 - 它不会对编译速度产生任何可衡量的影响。

  2. 绝对应该在头文件中使用命名空间来声明函数,类,全局等。你所做的是在头文件中使用using语句 - 它是不可能在包含它的源文件中取消使用某些内容,并且不应强制包含者向全局范围添加额外的内容。如果您需要在标题中使用其他名称空间中的内容,请完全限定每个名称。有时可能会很痛苦,但这是正确的做法。

  3. 示例:

    // WRONG!
    using namespace std;
    class MyClass
    {
        string stringVar;
    };
    
    // RIGHT
    class MyClass
    {
        std::string stringVar;
    };
    

    至于其他命名空间中的类的前向声明,你已经完全正确了。只需记住,当您在标题中引用AnotherFoo时,始终将AnotherNameSpace::AnotherFoo限定为{{1}}。实际上,前向声明是打破循环依赖的唯一方法。

答案 1 :(得分:7)

  1. 我听说有评论 在包括警卫之前可以导致 一些编译器错过了 优化。如果守卫是 第一件事,编译器可能 认识到成语,甚至不认识 麻烦打开标题 后续包括。在我自己 代码,注释通常在...之前 包括警卫。我没有 打扰测试,看看是否有 是否有任何影响。我可能永远不会(但如果其他人这样做,我会对结果感兴趣)。

  2. 当然标题应该合并 名称空间 - 否则没有 有用的可能在里面 命名空间。但是,就像你一样 提到,标题不应该 '导入'(想要更好的词) 命名空间成为编译单元 使用'using'指令。

答案 2 :(得分:3)

关于#1,我不知道有任何具体论据支持或反对。许多公司都有一项政策,其中版权声明必须是文件中的第一项之前的任何其他内容或任何有意义的代码(可能假设您在吸收任何代码之前阅读版权)。为此,#IFNDEF已经是代码。从可用性的角度来看,将版权放在首位是有道理的,因为眼睛忽略了它们。但是,任何描述模块的内容都应该在我看来#ifndef之后。

答案 3 :(得分:2)

1)由于评论实际上没有做任何事情,我怀疑它是否重要。从技术上讲,#include复制和粘贴,所以将注释放在标题保护之外可能意味着预处理器的工作量更大。我不知道大多数编译器是否足够聪明以便对此进行优化(即,如果它们在预处理器步骤之前删除了注释),但在达到数万个头文件之前,您可能不会注意到。

2)这是正确的。如果你想将一个类放在一个名称空间中,并且该类将在头文件中声明,那么它应该在名称空间内声明,因此它应该在头文件中。是的,这就是你如何向前宣布。是的,它是避免循环依赖的主要工具(你也可以改变你的设计,但原则上循环性没有任何问题,前提是这两个类只是通过引用或指针相互引用而不是调用任何方法)

答案 4 :(得分:2)

  1. 我不认为添加评论有任何影响,正如亚当对这篇文章的回答所指出的那样。

  2. 我在头文件中使用了自己的命名空间,如果你定义自己的字符串类,那么它会与std命名空间字符串类冲突。

  3. 完全使用“using”关键字并没有错(因为它为您提供了很多便利,而且在所有变量之前输入的次数要少得多)