我对这个问题有一些疑问,但首先让我给你一些代码:
example.hpp
#ifndef EXAMPLE_H_
#define EXAMPLE_H_
using namespace std;
void say_something(string something);
#endif
example.cpp
#include <string>
#include <iostream>
#include "example.hpp"
void say_something(string something)
{
cout << something << '\n';
}
的main.cpp
#include <iostream>
#include <string>
#include "example.hpp"
using namespace std;
int main()
{
string hello = "Hello world!";
say_something(hello);
return 0;
}
现在,我的问题是:
答案 0 :(得分:3)
我应该在标题example.hpp中放置example.cpp所需的所有头文件,还是应该像上面的示例一样将它们保存在example.cpp中?
将头文件保持最小。
头文件提供函数声明。函数声明取决于<string>
中的内容,而不取决于<iostream>
中的内容。因此,标头文件应包含<string>
而不包含<iostream>
。
如果头文件包含不必要的内容,则头文件的用户也将包含那些不必要的内容。
C ++在这种情况下如何工作:我在main.cpp和example.cpp中都包含了'string'和'iostream'... C ++编译器是否会链接(或者你会发现更多的术语)使用字符串和iostream标题两次该程序?我应该只在example.cpp
中放置字符串和iostream标头
C ++源代码不与标题链接。每当您编写#include <string>
时,预处理器(概念上)都会复制名为“string”的整个头文件并粘贴到#include <string>
行。预编译在编译和链接之前进行。
最后,我应该在头文件本身(example.hpp)或实现(example.cpp)中使用我将用于示例头的命名空间吗?
永远不要在头文件的全局范围内写using namespace std;
。由于#include
的复制和粘贴特性,using-directive将感染包含标头的其他文件。如果有文件想要使用say_something
但又不想using namespace std
该怎么办?
答案 1 :(得分:1)
不,你不应该。头文件应该只包含它需要的头文件。我是否应该将example.cpp所需的所有头文件放入其中 标题example.hpp或者我应该将它们保存在example.cpp中 上面的例子?
C ++在这种情况下如何工作:我在main.cpp和example.cpp中都包含了'string'和'iostream'... C ++编译器是否会链接(或者你会发现更多的术语)使用字符串和iostream标题两次该程序?我应该只在example.cpp
中放置字符串和iostream标头
由于包含警卫,编译器不会将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
。这不会引发编译错误,因为您已在<string>
之前添加了example.hpp
。
如果您在其他文件中使用example.hpp
而未包含<string>
,会发生什么情况呢?您将收到编译错误,因为您的标头使用std::string
而您尚未包含std::string
。
答案 2 :(得分:0)
- 我应该在标题 example.hpp 中放置 example.cpp 所需的所有头文件,还是应该将它们保存在示例中。 cpp 就像上面的例子一样?
将头文件包含在所需的每个文件中。不要担心重复。
- C ++在这种情况下如何工作:我在 main.cpp 和 example.cpp 中包含了'string'和'iostream'...是C ++编译器会用字符串和iostream头文件连接两次(或者你会发现更合格的任何术语)程序?我应该只将字符串和iostream标题放在 example.cpp
中
头文件本身确保其内容仅在任何翻译单元中包含一次。这是通过#ifdef EXAMPLE_H_
测试实现的。
- 最后,我是否应该在标题本身( example.hpp )或实现中添加我将用于示例标题的命名空间( example.cpp 强>)?
从不将using namespace ...
置于头文件永远的全局范围内。
如果您必须使用using namespace ...
,请仅在您自己的命名空间或函数中使用它。即使这样,也不建议将它用于大型名称空间,例如std
,其中包含每个人一直使用的数千个非常常见的符号。
理想情况下,您应该只在源using namespace ...
文件中使用.cpp
。但是(如前所述)对于应该在您自己的命名空间中逻辑存在的小命名空间,有时将它包含在标头的非全局部分中是合适的。