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

23

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

1 - 在注释之后放置 include guards

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

Herb Sutter在他的《C++编程规范》一书中表示,像上面那样的代码存在问题。他认为"#ifndef"语句应出现在头文件的第一行。我并不十分认同这种说法。你们在头文件中是否这样做了呢?

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个回答

19
  1. 头文件保护宏的位置和注释只是风格问题 - 它不会对编译速度产生任何可衡量的影响。

  2. 在头文件中声明函数、类、全局变量等应该绝对使用命名空间。但是,不应该在头文件中使用 using 语句 - 在包含它的源文件中取消使用是不可能的,并且你不应该强制包含者向全局作用域添加额外的内容。如果需要在头文件中使用其他命名空间中的内容,请完整限定每个名称。有时可能会很麻烦,但这确实是正确的做法。

例子:

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

// RIGHT
class MyClass
{
    std::string stringVar;
};

关于其他命名空间中类的前向声明,你说得完全正确。只需记住在头文件中引用AnotherFoo时始终要加上限定符AnotherNameSpace::AnotherFoo。事实上,前向声明是打破循环依赖的唯一方法。


7
  1. 有人说在预编译指令前添加注释可能会导致某些编译器错过一些优化。如果预编译指令是第一件事,编译器可能会识别出常用的语法,然后无需打开头文件进行后续包含操作。在我的代码中,注释通常位于预编译指令之前。我从未测试过这是否会产生任何影响。我也不会去测试它(但如果其他人测试了,我会很感兴趣)。

  2. 当然,头文件应该包含命名空间 - 否则就不能将任何有用的内容放入命名空间中。然而,正如你所提到的,头文件不应该使用‘using’指令将命名空间导入编译单元中。


3

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


2

1) 由于注释实际上并不起作用,我怀疑它并不重要。但从技术上讲,#include会进行复制和粘贴,因此将注释放在头文件保护之外可能会增加预处理器的工作量。我不知道大多数编译器是否足够聪明以优化此操作(即在预处理器步骤之前剥离注释),但您可能直到达到成千上万个头文件时才会注意到。

2) 这是正确的。如果您想将类放在命名空间中,并且该类将在头文件中声明,那么它应该在命名空间内声明,因此应该在头文件中包含命名空间。是的,这就是正好可以进行前向声明的方式。而且,它是避免循环依赖的主要工具(您也可以更改设计,但原则上循环性并没有错,只要所涉及的两个类仅通过引用或指针相互引用而不调用任何方法即可)。


2
  1. 我认为添加注释并不会影响性能,正如Adam在这篇帖子中所指出的。

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

准确使用"using"关键字并不是错误的(因为它给你带来了很多方便,在所有变量之前要输入的内容也少了很多)。


5
在源代码文件中,使用 "using" 并没有错,但在头文件中使用则是非常错误的。 - Adam Rosenfield

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接