跳转至

命名空間

概述

C++ 的 命名空間 機制可以用來解決複雜項目中名字衝突的問題。

舉個例子:C++ 標準庫的所有內容均定義在 std 命名空間中,如果你定義了一個叫 cin 的變量,則可以通過 cin 來訪問你定義的 cin 變量,通過 std::cin 訪問標準庫的 cin 對象,而不用擔心產生衝突。

聲明

下面的代碼聲明瞭一個名字叫 A 的命名空間:

1
2
3
4
5
namespace A {
int cnt;

void f(int x) { cnt = x; }
}  // namespace A

聲明之後,在這個命名空間外部,你可以通過 A::f(x) 來訪問命名空間 A 內部的 f 函數。

命名空間的聲明是可以嵌套的,因此下面這段代碼也是允許的:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
namespace A {
namespace B {
void f() { ... }
}  // namespace B

void f() {
  B::f();  // 實際訪問的是 A::B::f(),由於當前位於命名空間 A
           // 內,所以可以省略前面的 A::
}
}  // namespace A

void f()  // 這裏定義的是全局命名空間的 f 函數,與 A::f 和 A::B::f
          // 都不會產生衝突
{
  A::f();
  A::B::f();
}

using 指令

聲明瞭命名空間之後,如果在命名空間外部訪問命名空間內部的成員,需要在成員名前面加上 命名空間::

有沒有什麼比較方便的方法能讓我們直接通過成員名訪問命名空間內的成員呢?答案是肯定的。我們可以使用 using 指令。

using 指令有如下兩種形式:

  1. using 命名空間::成員名;:這條指令可以讓我們省略某個成員名前的命名空間,直接通過成員名訪問成員,相當於將這個成員導入了當前的作用域。
  2. using namespace 命名空間;:這條指令可以直接通過成員名訪問命名空間中的 任何 成員,相當於將這個命名空間的所有成員導入了當前的作用域。

因此,如果執行了 using namespace std;,就會將 std 中的所有名字引入到全局命名空間當中。這樣,我們就可以用 cin 代替 std::cin,用 cout 代替 std::cout

using 指令可能會導致命名衝突!

由於 using namespace std; 會將 std 中的 所有名字 引入,因此如果聲明瞭與 std 重名的變量或函數,就可能會因為命名衝突而導致編譯錯誤。

因此在工程中,並不推薦使用 using namespace 命名空間; 的指令。

有了 using 指令,C++ 語法基礎 中的代碼可以有這兩種等價寫法:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#include <iostream>

using std::cin;
using std::cout;
using std::endl;

int main() {
  int x, y;
  cin >> x >> y;
  cout << y << endl << x;
  return 0;
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include <iostream>

using namespace std;

int main() {
  int x, y;
  cin >> x >> y;
  cout << y << endl << x;
  return 0;
}

應用

在一些具有多個子任務的問題中,我們可以對每個子任務各開一個命名空間,在其中定義我們解決該子任務所需要的變量與函數,這樣各個子任務間互不干擾,會在一定程度上方便調試,也會改善程序的可讀性。