C++名稱空間

名稱空間是C++為了防止寫程式時命名發送衝突而設計出來的,其實和文件夾類似,不同名稱空間下的名稱可以相同。
接觸過C++的人都應該對using namespace std很熟悉,這就是大家最常見的名稱空間應用,叫做using編譯指令,其中std是一個名稱空間的名字。

C++提供了兩種機制來簡化對名稱空間中名稱的使用:

  1. using聲明(例如:using std::cout)
  2. using編譯指令(例如:using namespace std)

先我們來了解聲明是名稱空間,看程式碼

#include <iostream>

namespace nsp {
    int a = 0;
    void hello()
    {
        std::cout << "Hello!" << std::endl;
    }
}

int main()
{
    std::cout << nsp::a << std::endl;
    nsp::hello();
}

程式碼中定義了名稱空間 nsp,其中包含兩個名稱 a 和 hello,如果不使用 using 命令,那就只能用域解析運算符::來進行使用了。

名稱空間相當於將一些名稱打包,然後給這個包取個名字,通過名稱空間的名字和域解析運算符::就可以使用裡面的名稱了

使用 using 聲明,就是把裡面的一個名稱單獨取出來使用,如:`using nsp::hello’,要記住函數名稱後面不能加括弧
使用 using 編譯指令,就是把包給解開,使得所有名稱都可以使用,如:’using namespace nsp’

使用 using 指令後,名稱的可用範圍時從使用處起,到該作用域結束為止
例如如果是在函數里用,就是從使用位置開始到函數結束的位置,在這個範圍里可以直接使用釋放出來的名稱

::還可以用於訪問被局部變數覆蓋了的全局變數,如test.cpp中程式碼,其中::x表示的就是全局duoble型變數 x:

#include <iostream>

double x = 27.0;

void test(int a)
{
    int x = a;
    {
        using std::cout;
        char x = 'Q';
        cout <<  "最內層x = " << x << "\n"
             <<  "全局::x = " << ::x << std::endl;
    }
    using std::endl;
    std::cout << "中間層x = " << x << '\n' << endl;
}

下面是文件main.cpp的內容:

extern void test(int x); // extern 可以省略,不省略的好處是可以明確指出這是在外部文件定義的函數

namespace nsp {
    int a = 7;
}

int main()
{
    using namespace nsp;
    test(a);    // a 為 7
    int a = 9;
    test(a);    // a 為 9
}

注意:使用 using 聲明後,不可在同一級別的作用域里再次聲明一樣的名稱,因為 using 聲明也相當於聲明,而 C++ 不允許在同一文件中重複聲明,不過可以在不同級別的作用域里再次聲明,一層花括弧就是更深一層的作用域。不過 using 編譯指令就沒有這個限制了,你還是可以重複聲明一次相同的名稱。

使用名稱空間還需要注意:

  1. 名稱空間可以嵌套,但不可以在程式碼塊中,例如在函數中定義名稱空間
  2. 同一名稱空間可分布在不同的文件中,也可以在同一文件的不同位置
  3. 要使用名稱空間中在其他文件里的變數或者函數,需要在本文件的名稱空間中聲明為外部變數,函數也一樣

如下面程式碼:

// test.cpp
#include <iostream>

namespace nsp
{
    double x = 27.0;

    void test(int a)
    {
        using namespace std;
        cout << a << endl;
    }
}
// main.cpp
namespace nsp {
    int a = 7;
    extern double x;        // 必須加 extern 否則會報錯
    extern void test(int);  // 可省略 extern
}

namespace nsp {
    int b = 8;
}

int main()
{
    using namespace nsp;
    test(a);    // a 為 7
    test(b);    // b 為 8
    int a = 9;
    test(a);    // a 為 9
    test(x);    // x 為 27
}

下面是使用頭文件的情況,一般在項目中都會把聲明放到頭文件中,然後再用同名稱的.cpp文件來進行實現

// test.h
#ifndef TEST_H_INCLUDED
#define TEST_H_INCLUDED

namespace TEST
{
    const double x = 27.0;  // 溫馨提示:頭文件中不要有變數
    void test(int);
}

#endif // TEST_H_INCLUDED

// test.cpp
#include <iostream>
#include "test.h"

namespace TEST
{
    void test(int a)
    {
        using namespace std;
        cout << a << endl;
    }
}
// main.cpp
#include "test.h"

namespace  TEST {
    int a = 7;
}

namespace TEST {
    int b = 8;
}

int main()
{
    using namespace TEST;
    test(a);    // a 為 7
    test(b);    // b 為 8
    int a = 9;
    test(a);    // a 為 9
    test(x);    // x 為 27
}

預編譯指令#include "test.h"的作用其實就是將 test.h 文件中的內容替換掉這一行。

我是七進位,一個被編程耽誤的吉他手