这是在C++中使用头文件的正确方法
Which is the correct way to use a header file in C++?
我对这个主题有一些疑问,但首先让我给你一些代码:
例子.hpp
#ifndef EXAMPLE_H_
#define EXAMPLE_H_
using namespace std;
void say_something(string something);
#endif
示例.cpp
#include <string>
#include <iostream>
#include "example.hpp"
void say_something(string something)
{
cout << something << 'n';
}
主.cpp
#include <iostream>
#include <string>
#include "example.hpp"
using namespace std;
int main()
{
string hello = "Hello world!";
say_something(hello);
return 0;
}
现在,我的问题是:
- 我应该把 example.cpp 需要的所有头文件放在标题 example.hpp 中,还是应该将它们保留在示例中.cpp就像上面的例子一样?
- 在这种情况下,C++将如何工作:我在main和example.cpp和example中都包含了"string"和"iostream".cpp...C++编译器是否会使用字符串和 iostream 标头将程序链接(或任何您认为更合格的术语)两次?我应该只把字符串和 iostream 标头放在示例中吗.cpp
- 最后,我应该将要用于示例标头的命名空间放在标头本身(example.hpp)还是实现(example.cpp)中?
我应该把 example.cpp 需要的所有头文件放在标题 example.hpp 中,还是应该将它们保留在示例中.cpp就像上面的例子一样?
保持头文件最小。
头文件提供函数声明。函数声明依赖于<string>
中的事物,但不依赖于<iostream>
中的事物。因此,头文件应包含不带<iostream>
<string>
。
内容,则头文件的用户也将包含这些不必要的内容。
在这种情况下,C++将如何工作:我在main和example.cpp中都包含了"string"和"iostream".cpp...C++编译器是否会使用字符串和 iostream 标头将程序链接(或任何您认为更合格的术语)两次?我应该只把字符串和 iostream 标头放在示例中吗.cpp
C++源不与标头链接。每当你写#include <string>
时,预处理器(概念上)复制名为"string"的整个头文件并粘贴到#include <string>
行。预处理发生在编译和链接之前。
最后,我应该将要用于示例标头的命名空间放在标头本身(example.hpp)还是实现(example.cpp)中?
切勿在头文件的全局范围内写入using namespace std;
。由于#include
的复制和粘贴性质,using-指令会感染其他包含标头的文件。如果有一个文件想要使用say_something
但不想using namespace std
怎么办?
我应该把我的所有头文件放在示例.cpp将需要 标题 example.hpp 还是我应该将它们保留在示例中.cpp例如 上面的例子?
不,你不应该。头文件应仅包含它所需的头文件。
在这种情况下,C++将如何工作:我在main和example.cpp中都包含了"string"和"iostream".cpp...C++编译器是否会使用字符串和 iostream 标头将程序链接(或任何您认为更合格的术语)两次?我应该只把字符串和 iostream 标头放在示例中吗.cpp
由于包含保护,编译器不会链接两次string
或iostream
。例如,它只会打开string header
,并在包含保护告诉编译器它已被包含时立即返回。
最后,我应该将要用于示例标头的命名空间放在标头本身(example.hpp)还是实现(example.cpp)中?
这与包含问题相同。如果你在头文件中放置一个"using namespace std;
",那么包含它的所有其他文件都将被强制使用整个命名空间。顺便说一下,这不是一件好事。
因此,在实现中use namespace std
(在包含所有标头之后)并不邪恶。
在你的头文件中,在函数体内使用"using namespace std
"或只是"using std::string
"也可以,它们将仅限于函数体的范围。
void somef(std::string str_arg)
{
using std::string;
string str;
// This is not evil either.
using namespace std;
string str;
}
void somef2() {
//string str; //error
}
如果somef
是类的方法,常见的方法是使用 typedef,例如:
class MyClass
{
typedef std::string string_type;
//using string_type = std::string; //C++11
string_type data_member;
void somef(string_type str)
{
string_type local_str;
}
void somef2() {
string_type local_str; // works
}
};
#include <string> #include <iostream> #include "example.hpp"
我想说这也是使用头文件的一个不好的顺序。假设example.hpp
使用 std::string
。这不会引发编译错误,因为您在 example.hpp
之前已包含<string>
。
如果您在另一个文件中使用 example.hpp
而没有在它之前包含<string>
,会发生什么情况?您将收到编译错误,因为您的标头使用 std::string
并且您没有包含std::string
.
- 我应该把 example.cpp 需要的所有头文件放在标题 example.hpp 中,还是应该将它们保留在示例中.cpp就像上面的例子一样?
将头文件包含在需要它们的每个文件中。不用担心重复。
- 在这种情况下,C++将如何工作:我在main和example.cpp和example中都包含了"string"和"iostream".cpp...C++编译器是否会使用字符串和 iostream 标头将程序链接(或任何您认为更合格的术语)两次?我应该只把字符串和 iostream 标头放在示例中吗.cpp
头文件本身确保其内容在任何翻译单元中仅包含一次。这是通过#ifdef EXAMPLE_H_
测试实现的。
- 最后,我应该将要用于示例标头的命名空间放在标头本身(example.hpp)还是实现(example.cpp)中?
永远不要将using namespace ...
放在头文件的全局范围内。
如果必须使用using namespace ...
请仅在自己的命名空间或函数中使用它。即便如此,也不建议将其用于像std
这样的大型命名空间,其中包含数千个每个人都一直在使用的非常常见的符号。
此外,理想情况下,您应该只在源.cpp
文件中使用using namespace ...
。但是(如前所述)对于逻辑上应该存在于您自己的命名空间中的小型命名空间,有时将其包含在标头的非全局部分中是合适的。
- 如何使用curlpp通过POST方法上传文件和json数据
- 一种在C++中读取TXT配置文件的简单方法
- 在 cpp 文件中隐藏采用模板参数引用的方法
- 在C++中包含原型文件的正确方法是什么?
- 通过比较C++中的行在 txt 文件中搜索的最简单方法是什么?
- 不带预处理器的调用方法/文件的文件名/行号
- 引用文件的适当方法是什么?
- 在文件中写入而不是在 c++ 中使用 "<<" 的替代方法?
- 查找定义我的 C/C++ 函数/宏的文件比'grep'更简单的方法
- 读取大文件(>2GB)(文本文件包含以太网数据)并通过不同参数随机访问数据的最佳方法是什么?
- 在C++中创建文件夹选取器对话框的最简单方法是什么?
- C++:std::ofstream 方法 open() 在第二次迭代时擦除打开的 ifstream 文件
- 如何使用 C/C++ 和 system() 系统调用以外的其他方法在 Linux 中获取文件功能?
- 创建进行生产构建并创建调试信息的C++生成文件的最佳方法?
- 是否有正确的方法对生成文件中的对象文件使用模板命令?(C++)
- 将位字符串转储到二进制文件的最佳方法是什么
- 在目录中查找所有.cpp.h文件(include,src等)的传统方法
- 是在DEX文件方法计数中计数的本机C 方法
- C++更新 txt 文件方法
- h头文件方法混乱