应该“#include”和“使用”声明在头文件和实现文件中重复(C++)?
我对 C++ 相当陌生,但我的理解是 #include 语句本质上只是将 #included 文件的内容转储到该语句的位置。这意味着如果我的头文件中有许多“#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
I'm fairly new to C++, but my understanding is that a #include statement will essentially just dump the contents of the #included file into the location of that statement. This means that if I have a number of '#include' and 'using' statements in my header file, my implementation file can just #include the header file, and the compiler won't mind if I don't repeat the other statements.
What about people though?
My main concern is that if I don't repeat the '#include', 'using', and also 'typedef' (now that I think of it) statements, it takes that information away from the file in which it's used, which could lead to confusion.
I am just working on small projects at the moment where it won't really cause any issues, but I can imagine that in larger projects with more people working on them it could become a significant issue.
An example follows:
UPDATE: my function prototypes for 'Unit' have string, ostream and StringSet among their return types and parameters - I am not including anything in my header file that is used only in the implementation file.
//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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
using-directive(
using namespace std;
)不应驻留在标头中,除非它包含在函数中。这是不好的做法。标头的每个用户不太可能都希望对给定名称空间中的所有内容进行不合格的查找;包含不相关的标头可能会导致意外的歧义和编译失败。就我个人而言,出于同样的原因,我避免在函数内部使用 using-directive,但这通常被认为危害较小。应谨慎使用类型别名(通过
typedef std::string string;
或using string = std::string;
)。类型定义是有意义的,所以你不应该重新声明它。例如,这是一个错误:因为类型冲突。
using-declaration(
using std::string;
或using std::memcpy;
)使 非限定名称查找。当获得依赖参数的查找正确时,它非常有用,而这通常不会'除非你正在写一个库,否则没关系。根据您是否引入类型或函数,建议会有所不同。将使用声明与类型的方式想象为类型别名:同一个名称下有多个定义是没有意义的。对于函数,您真正要做的就是扩展重载解析以包含更多内容(尽管通常没有必要)。对于重复
#include
,您应该首先考虑是否确实需要在标头中包含该文件。也许转发声明适合您需要。A using-directive (
using namespace std;
) should not reside in a header unless it is contained within a function. It is bad practice. It is unlikely that every user of your header wants unqualified lookup for everything in a given namespace; the inclusion of unrelated headers can lead to unexpected ambiguity and compilation failures. Personally, I avoid the using-directive inside of functions for the same reasoning, but this is generally considered less harmful.A type alias (either through
typedef std::string string;
orusing string = std::string;
) should be used carefully. Type definitions have meaning, so you should never redeclare it. For example, this is an error:because of conflicting types.
A using-declaration (
using std::string;
orusing std::memcpy;
) makes a symbol accessible for unqualified name lookup. It is extremely useful when getting for argument-dependent lookup correct, which usually doesn't matter unless you're writing a library. The advice is different depending on if you are bringing in a type or a function. Think of using-declarations with types in the same manner as a type alias: It does not make sense to have multiple definitions under the same name. With functions, all you are really doing is extending overload resolution to include a few more things (although it is usually not necessary).For repeating
#include
, you should consider if you actually need to include the file in the header in the first place. Perhaps a forward declaration fits your needs.using
标头中的语句(除非在函数作用域内)...在标头中添加using
会污染包括标头在内的所有源的命名空间。您不需要关心某些包含是否多余。标头保护和预编译器优化可以为您处理这个问题。
您应该能够单独操作每个文件。
例如,假设您在标头和源代码中使用
std::string
,但是,作为“优化”,您只在标头中包含了该字符串...如果您后来发现不再需要标头中的字符串,并且想要删除它(代码清理,以及所有...),您将不得不修改源以包含该字符串。现在,让我们假设您有十个源,包括标头...现在,当然,您可以对此规则有例外(例如,预编译标头,甚至标头的唯一目的是出于礼貌而进行多次包含),但是默认情况下,您应该拥有自给自足的头文件和源文件(即包含它们使用的任何内容的文件,不多也不少)。
using
statement in headers (unless inside function scopes)... Addingusing
in the header will pollute the namespaces of all the sources including the header.You don't need to care if some includes are redundant. Header guards and precompiler optimizations are there to handle that for you.
You should be able to manipulate each file in isolation.
For example, let's say you use the
std::string
in the header and in the source, but, as an "optimization", you only included the string in the header... If you discover later you don't need anymore the string in the header, and want to remove it (code cleaning, and all...), you will have to modify the source to include the string. Now, let's imagine you have TEN sources including the header...Now, of course, you can have exceptions to this rule (for example, precompiled headers, or even headers woe sole aim is to do multiple includes as a courtesy), but by default, you should have self-sufficient header and source files (i.e. files that include anything they use, no more no less).
将头文件保持在最低限度。这意味着尽可能少的包含。 .cpp 文件通常包含相应的标头以及实现所需的任何其他标头。
Keep the header files to a minimum. This means as little include's as feasible. the .cpp file will usually include the corresponding header as well as any other headers necessary for implementation.
就像 Travis 所说,头文件中不应该有
using
语句,因为这意味着它们将包含在包含该头文件的所有翻译单元中,这可能会导致混乱的问题。如果我只需要 cpp 文件中头文件的功能,我只将其包含在该 cpp 文件中。对于大型项目来说这是一个很好的做法,因为这意味着编译器的工作量更少。另外,只要有可能,我都会在标头中使用前向声明而不是包含(并且再次将标头包含在 cpp 文件中)。
Like Travis said, you shouldn't have
using
statements in a header file because that means they will be included in all the translation units that include that header file, which can cause confusing issues.If I only require the functionality from a header file in a cpp file, I only include it in that cpp file. It's good practice for larger projects because it means less work for the compiler. Also, wherever possible, I use forward declarations in the headers instead of includes (and again, include the headers in the cpp file).
在头文件中使用
using
语句被认为是一种不好的形式,除非您有意将符号复制到不同的命名空间中。在cpp文件中使用就可以了。每个
typedef
在代码库中只能存在一次。如果需要在多个 cpp/h 文件中使用,则应该将其放在头文件中。重复它们会给你带来很多痛苦。头文件应该包含它需要的所有
#include
语句,而不包含其他语句。如果仅提到指向类的指针,则使用前向声明而不是包含标头。仅在 cpp 文件内需要的任何其他包含内容都应该放在那里。重复标头中的包含内容是可以的,但不是必需的。这只是一种风格选择。It's considered bad form to have a
using
statement in a header file at all, unless you are intentionally duplicating a symbol into a different namespace. It's ok to use in a cpp file.Each
typedef
should exist only once in your codebase. That should be in a header file if it needs to be used in multiple cpp/h files. Duplicating them will cause you much grief.A header file should have all the
#include
statements that it needs, and no others. If only pointers to a class are mentioned then use a forward declaration rather than including the header. Any other includes that are required only inside the cpp file should go there. Repeating the includes from the header is ok, but not required. It's just a style choice.