在 C++ 中,**命名空间**是一组相关的名称或标识符(函数、类、变量)的集合,它有助于将这些标识符与来自其他命名空间或全局命名空间的类似标识符区分开来。
C++ 标准库的标识符定义在一个名为 std 的命名空间中。
为了使用任何属于标准库的标识符,我们需要指定它属于 std 命名空间。一种方法是使用作用域解析运算符 ::。例如,
std::cout << "Hello World!";
这里,我们在 cout 前使用了 std:: 代码。这告诉 C++ 编译器我们使用的 cout 对象属于 std 命名空间。
C++ std 标识符
<iostream>、<string>、<vector> 等标准头文件提供的所有标准库标识符都声明在 std 命名空间中。
例如,标识符 cin 和 cout 定义在 std 命名空间中 <iostream> 的标准头文件中。
利用 std 标识符
我们可以通过以下方式在程序中使用 std 命名空间的标识符:
::运算符using声明using指令
std Namespace Using :: Operator
我们访问 std 命名空间中标识符的第一种方式是直接用前缀 std:: 限定标识符。这里,
std是 C++ 标准库命名空间::是作用域解析运算符
例如,
#include <iostream>
int main() {
std::string first_name;
std::cout << "Enter your first name: ";
std::cin >> first_name;
std::cout << "Hello " << first_name << "!" << std::endl;
std::cout << "Welcome!";
return 0;
}
输出
Enter your first name: Marty Hello Marty! Welcome!
在上面的示例中,我们通过编写 std:: 来直接使用作用域解析运算符 :: 从 std 命名空间访问标识符。
请注意,我们在 string、cin、cout 和 endl 前面加上了 std:: 前缀,写法如下:
std::stringstd::cinstd::coutstd::endl
如果从上面的代码中删除 std:: 前缀,我们会收到一个错误。
std Namespace With using Declaration
我们可以借助 **using 声明** 将选定的标识符引入当前作用域。要做到这一点,我们使用 using 关键字。
这样做之后,我们就无需在指定的标识符前加上 std:: 前缀了。例如,
#include <iostream>
// using declartion for cout, endl and string
using std::cout;
using std::endl;
using std::string;
int main() {
string first_name ;
cout << "Enter your first name: ";
std::cin >> first_name;
cout << "Hello " << first_name << "!" << endl;
cout << "Welcome!";
return 0;
}
输出
Enter your first name: Scarlet Hello Scarlet! Welcome!
在上面的示例中,我们使用了 using 声明来引入我们想从 std 命名空间使用的标识符。
using std::cout;
using std::endl;
using std::string;
在这里,我们告诉编译器,我们只想将 cout、endl 和 string 这几个标识符从标准命名空间引入到当前作用域。
这使得我们不必在每次需要访问这些标识符时都显式添加 std:: 前缀。
请注意,我们在程序中使用了 std::cin 而不是 cin。
std::cin >> first_name;
这是因为我们在 using 声明中没有包含 std::cin。
std Namespace With using Directive
我们可以使用 **using 指令** 将 std 命名空间 **的所有标识符** 引入,就好像它们是全局声明的一样。要做到这一点,我们使用 using 关键字。
通过这样做,我们可以:
- 避免使用
std::前缀 - 避免反复使用
using声明
例如,
#include <iostream>
// using directive
using namespace std;
int main() {
string first_name ;
cout << "Enter your first name: ";
cin >> first_name;
cout << "Hello " << first_name << "!" << endl;
cout << "Welcome!";
return 0;
}
输出
Enter your first name: Jack Hello Jack! Welcome!
在上面的示例中,我们使用了 using **指令** 将 std 命名空间的所有标识符引入我们的程序,包括 string、cout、cin 和 endl 标识符。
注意事项
- **using 声明** 只将命名空间中指定的标识符引入当前作用域。
- **using 指令** 将命名空间的所有标识符引入当前作用域。
不良实践:using namespace std
由于 using namespace std 将 std 命名空间的所有标识符引入全局命名空间,这可能会与其他命名空间产生命名冲突。例如,除了 std 命名空间中的 cout 之外,可能还有其他具有 cout 名称的实体。
因此,如果我们同时使用那个其他命名空间(包含另一个 cout 实体)和 std 命名空间,那么编译器将不知道使用哪个 cout。结果是,每次使用 cout 时都会出现错误。
让我们来看一个例子,
#include <iostream>
using namespace std;
// function template for swapping numbers
template <class T>
void swap (T& a, T& b) {
cout << "Before Swapping\na = " << a << " and b = " << b << endl;
T temp = a;
a = b;
b = temp;
cout << "After swapping\n";
cout << "a = " << a << " and " << b << " = " << b << endl;
}
int main() {
int a = 1;
int b = 2;
swap(a, b);
return 0;
}
输出
error: call of overloaded 'swap(int&, int&)' is ambiguous
在上面的示例中,我们使用了一个 函数模板 创建了自己的 swap() 函数版本。然后我们尝试使用整数 a = 1 和 b = 2 调用 swap() 函数,
swap(a, b);
swap() 函数接收两个整数并交换它们,同时显示交换前后 a 和 b 的值。但是如果我们尝试运行代码,会收到一个错误。
为什么会收到错误?
这里,我们因为程序中的以下代码而收到错误:
using namespace std;
这是一个 **using 指令**,它将标准命名空间的所有标识符引入当前命名空间。但是 std 命名空间包含了它自己的 swap() 函数。
因此,编译器无法确定使用哪个版本的 swap():是 std::swap() 还是我们创建的自定义函数。
为了避免此错误,我们必须从程序中删除 using namespace std; 代码。
潜在的专业问题
假设你正在处理一个大型程序或项目。比如说,你正在使用一个名为 swapLib 的库,它实现了自己的 swap() 函数。
如果你使用了 using namespace std,它可能会像我们的示例一样产生歧义,即是使用 swapLib 库中的 swap() 还是标准命名空间中的 swap()。
注意:如果你只使用标准库中的少量名称,最好使用 **using 声明** 来选择性地引入标识符。