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

时间:2021-12-07 15:06:37

I have the following doubts on header files usage.

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

1 - Include guards placing after comments

1 - 在评论后加入警卫

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

Herb Sutter says in his "C++ coding standards" book that code like the above is problematic. He is saying the "#ifndef" statements should appear in the first line of the header file. I haven't felt this as convincing. Is this followed by you guys/gals in header files?

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

2 - Using namespaces in header files

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

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

Is the above code using correct practice? I mean, do you use namespaces in header files? I know why importing a namespace in header file is pointless but what about a declaration like the above?

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

If the above one is the correct method, how do you do "forward declaration" of a class which is in another namespace? Is it like

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

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

namespace FooNameSpace{
    // Use AnotherFoo here
}
#endif

The "forward declaration" is the only method to avoid "cyclic dependency", correct?

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

5 个解决方案

#1


19  

  1. The order of the include guards and the comments is purely a matter of style - it won't have any measurable effect on speed of compilation.

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

  2. Namespaces absolutely should be used in header files for declaring functions, classes, globals, etc. What you should not do is use using statements in header files -- it's impossible to unuse something in a source file that includes it, and you shouldn't force includers to add extra stuff to the global scope. If you need to use things from other namespaces in your headers, fully qualify every name. It can be a pain sometimes, but it's really the right thing to do.

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

Examples:

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

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

As for forward declarations of classes in other namespaces, you've got it exactly right. Just remember to always qualify AnotherFoo as AnotherNameSpace::AnotherFoo when you reference it inside your header. Indeed, forward declarations are the only way to break cyclic dependencies.

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

#2


7  

  1. I've heard that having comments before the include guard can cause some compilers to miss an optimization. If the guard is the very first thing, the compiler may recognize the idiom and not even bother opening the header for subsequent includes. In my own code, comments normally precede the include guard. I haven't ever bothered testing to see if this has any impact or not. And I likely never will (but if someone else does, I'd be interested in the results).

    我听说在包含守卫之前发表评论会导致一些编译器错过优化。如果防护是第一件事,编译器可能会识别成语,甚至不打算打开后续包含的标题。在我自己的代码中,注释通常在include guard之前。我从来没有打扰过测试,看看这是否有任何影响。我可能永远不会(但如果其他人这样做,我会对结果感兴趣)。

  2. Of course headers should incorporate namespaces - otherwise nothing useful could ever be inside a namespace. However, as you mentioned, headers should not 'import' (for want of a better word) namespaces into a compilation unit with a 'using' directive.

    当然标头应该包含名称空间 - 否则在名称空间内不会有任何用处。但是,正如您所提到的,标题不应该“导入”(因为缺少更好的单词)命名空间到具有'using'指令的编译单元中。

#3


3  

Regarding #1, I am not aware of any concrete argument for or against. Many companies have a policy where the copyright notice has to be the first item in the file BEFORE anything else or any meaningful code (maybe the assumption is that you'll read the copyright before you absorb any code). For that purpose, #IFNDEF is already code. From a usability point of view, it makes sense to put the copyrights first because the eye ignores them. However, anything describing the module should come after the #ifndef in my opinion.

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

#4


2  

1) Since comments don't actually do anything, I doubt it matters much. Technically though, #include copy and pastes, so putting the comments outside the header guards can mean more work for the preprocessor. I don't know if most compilers are smart enough to optimize for this (i.e. if they strip comments before the preprocessor step) but you probably wouldn't notice until you reached tens of thousands of header files.

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

2) That's correct. If you want to put a class inside a namespace, and that class is going to get declared in a header file, well then it should be declared inside the namespace, which thus should be in the header file. And yes, that's how you forward declare exactly. And yes, it is the main tool for avoid cyclic dependency (you could also change your design, but there's nothing wrong with cyclicness in principle provided the two classes in question are only referring to each other by reference or pointer and not calling any methods).

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

#5


2  

  1. I don't think adding comments has any performance impact as pointed by Adam's answer to this post.

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

  2. I have used myself namespaces in header files, what if you define you own string class , so it would * with the std namespace string class.

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

Using the "using" keyword exactly is not wrong (since it gives you a lot of convenience and lot less to type before all your variables)

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

#1


19  

  1. The order of the include guards and the comments is purely a matter of style - it won't have any measurable effect on speed of compilation.

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

  2. Namespaces absolutely should be used in header files for declaring functions, classes, globals, etc. What you should not do is use using statements in header files -- it's impossible to unuse something in a source file that includes it, and you shouldn't force includers to add extra stuff to the global scope. If you need to use things from other namespaces in your headers, fully qualify every name. It can be a pain sometimes, but it's really the right thing to do.

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

Examples:

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

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

As for forward declarations of classes in other namespaces, you've got it exactly right. Just remember to always qualify AnotherFoo as AnotherNameSpace::AnotherFoo when you reference it inside your header. Indeed, forward declarations are the only way to break cyclic dependencies.

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

#2


7  

  1. I've heard that having comments before the include guard can cause some compilers to miss an optimization. If the guard is the very first thing, the compiler may recognize the idiom and not even bother opening the header for subsequent includes. In my own code, comments normally precede the include guard. I haven't ever bothered testing to see if this has any impact or not. And I likely never will (but if someone else does, I'd be interested in the results).

    我听说在包含守卫之前发表评论会导致一些编译器错过优化。如果防护是第一件事,编译器可能会识别成语,甚至不打算打开后续包含的标题。在我自己的代码中,注释通常在include guard之前。我从来没有打扰过测试,看看这是否有任何影响。我可能永远不会(但如果其他人这样做,我会对结果感兴趣)。

  2. Of course headers should incorporate namespaces - otherwise nothing useful could ever be inside a namespace. However, as you mentioned, headers should not 'import' (for want of a better word) namespaces into a compilation unit with a 'using' directive.

    当然标头应该包含名称空间 - 否则在名称空间内不会有任何用处。但是,正如您所提到的,标题不应该“导入”(因为缺少更好的单词)命名空间到具有'using'指令的编译单元中。

#3


3  

Regarding #1, I am not aware of any concrete argument for or against. Many companies have a policy where the copyright notice has to be the first item in the file BEFORE anything else or any meaningful code (maybe the assumption is that you'll read the copyright before you absorb any code). For that purpose, #IFNDEF is already code. From a usability point of view, it makes sense to put the copyrights first because the eye ignores them. However, anything describing the module should come after the #ifndef in my opinion.

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

#4


2  

1) Since comments don't actually do anything, I doubt it matters much. Technically though, #include copy and pastes, so putting the comments outside the header guards can mean more work for the preprocessor. I don't know if most compilers are smart enough to optimize for this (i.e. if they strip comments before the preprocessor step) but you probably wouldn't notice until you reached tens of thousands of header files.

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

2) That's correct. If you want to put a class inside a namespace, and that class is going to get declared in a header file, well then it should be declared inside the namespace, which thus should be in the header file. And yes, that's how you forward declare exactly. And yes, it is the main tool for avoid cyclic dependency (you could also change your design, but there's nothing wrong with cyclicness in principle provided the two classes in question are only referring to each other by reference or pointer and not calling any methods).

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

#5


2  

  1. I don't think adding comments has any performance impact as pointed by Adam's answer to this post.

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

  2. I have used myself namespaces in header files, what if you define you own string class , so it would * with the std namespace string class.

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

Using the "using" keyword exactly is not wrong (since it gives you a lot of convenience and lot less to type before all your variables)

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