23

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

1 - 包括在评论后放置的守卫

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

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

4

5 回答 5

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

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

例子:

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

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

至于其他命名空间中的类的前向声明,您完全正确。AnotherFoo只要记住AnotherNameSpace::AnotherFoo在标题中引用它时始终符合条件。事实上,前向声明是打破循环依赖的唯一方法。

于 2009-01-04T05:49:17.617 回答
7
  1. 我听说在包含保护之前有注释会导致一些编译器错过优化。如果守卫是第一件事,编译器可能会识别成语,甚至不会费心打开标题以进行后续包含。在我自己的代码中,注释通常在包含保护之前。我从来没有费心测试过这是否有任何影响。而且我可能永远不会(但如果其他人这样做,我会对结果感兴趣)。

  2. 当然,标头应该包含命名空间——否则命名空间内不可能有任何有用的东西。但是,正如您所提到的,标头不应使用“ using”指令将名称空间“导入”(为了更好的词)到编译单元中。

于 2009-01-04T05:59:56.673 回答
3

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

于 2009-01-04T05:54:08.103 回答
2

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

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

于 2009-01-04T05:54:59.570 回答
2
  1. 正如亚当对这篇文章的回答所指出的那样,我认为添加评论不会对性能产生任何影响。

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

准确地使用“using”关键字并没有错(因为它为您提供了很多便利,并且在所有变量之前输入的内容更少)

于 2009-01-04T06:03:02.113 回答