1. 程式人生 > >一 : using宣告、using指示及其作用域詳解

一 : using宣告、using指示及其作用域詳解

1. using 宣告:一個using宣告一次只能引入一個名稱空間成員,從using宣告點開始,直到包含該using宣告的作用域結尾,宣告的名字僅僅在該作用域是可見的,外部作用域中相同的名字被遮蔽,它可以出現在全域性作用域,區域性作用域或者名稱空間作用域中,類中的using宣告侷限於使用其基類中定義的名字;

using宣告將名字直接放入出現using宣告的作用域,好像using宣告是名稱空間成員的區域性別名一樣,這種宣告是區域性化的,名字僅僅在using宣告被包含的作用域有效;

一定記住using宣告是區域性的,它涉及到的作用域只有一個,就是從using宣告點開始,直到包含該using宣告的作用域結尾,別無他處;


有如下名稱空間:

//標頭檔案 named_namespace.h

#ifndef NAME_17_2_3
#define NAME_17_2_3
namespace name_17_2_3
{
  class AA
  {
    AA() {}
  };
  extern int name_17_2_3_fun(); //宣告
  extern int i; //宣告
}
#endif

//實現檔案 named_namespace.cpp
#include "named_namespace.h"
namespace name_17_2_3
{
  int name_17_2_3_fun() //定義
  {
    return 998;
  }
  int i; //定義
}
使用名稱空間的檔案:
#include <iostream>
#include "named_namespace.h"

using namespace std;
using name_17_2_3::i;  //using宣告,在全域性作用域宣告名稱空間name_17_2_3的成員變數i,全域性可見;
using name_17_2_3::name_17_2_3_fun;  //using宣告,聲明瞭名稱空間name_17_2_3的成員函式name_17_2_3_fun;
int i = 200; //全域性變數i,將與using宣告引入的名稱空間的成員變數i衝突
int main()
{
  cout << "i=" << i << endl; //呼叫哪一個 i 呢?
  cout << "name_17_2_3_fun():" << name_17_2_3_fun() << endl; //呼叫名稱空間name_17_2_3的成員函式

  return 0;
}
在上述程式碼中的全域性作用域中,有兩個變數 i 可見,一個是全域性變數 i ,另一個是using宣告引入的名稱空間name_17_2_3的成員變數i,因為using宣告處於全域性作用域,這時編譯就會出錯,因為兩個宣告衝突了,而成員函式則不衝突因為只有一個宣告;

如果將using name_17_2_3::i; 放入main函式,那這個using宣告就是區域性的,名稱空間name_17_2_3的成員變數i就是區域性變數,將會遮蔽全域性變數i,編譯通過,如果想使用全域性變數i時,可以使用作用域操作符::對i進行限定,例如:::i表示全域性變數i;

2. using指示:using指示使得特定名稱空間的所有名字可見,從using指示點開始(這點同using宣告一致),對名字可以不加限定符使用,直到包含using指示的作用域的末尾;using指示具有將名稱空間成員提升到包含名稱空間本身和usin指示的最近作用域的效果;

其實不太好理解的是最後一句話:“包含名稱空間本身的作用域” 和 “usin指示的最近作用域” 分別指的是哪個作用域,經過昨天一下午的試驗,今早上公交車上一路的琢磨,終於搞明白了,下邊進行詳細解釋:

例如:將上述程式碼的修改如下:

#include <iostream>
#include "named_namespace.h" //將名稱空間name_17_2_3插入到當前位置,也就是全域性作用域,相當於在此處定義名稱空間;

using namespace std;
using namespace name_17_2_3;  //using指示,處於全域性作用域,;
int i = 200; //全域性變數;
int main()
{
  //using namespace name_17_2_3;
  cout << "i=" << i << endl; //呼叫哪一個 i 呢?編譯器不知道應該使用哪個變數 i;
 
  return 0;
}

a:因為#include指令將標頭檔案包含的名稱空間name_17_2_3插入到了main之前,這與在main之前定義一個名稱空間是一樣的,main之前屬於全域性作用域,所以名稱空間name_17_2_3就被包含在了全域性作用域中,那這句話 “包含名稱空間本身的作用域“ 中的 “作用域” 指的就是全域性作用域了,那麼名稱空間name_17_2_3的所有成員自然而然就在全域性作用域中可見了,雖然在全域性作用域可見,但是,如果把using指示寫在main函式內部,那麼只有main函式內可以訪問所有成員名字,書上也有明確說明,詳細解釋可以接著往下看;

所以:上述程式碼中,在全域性作用域通過using指示的名稱空間name_17_2_3,好像name_17_2_3的所有成員在mai之前定義一樣,所以在使用變數 i 時將遇到編譯錯誤,不知道應該使用哪個位置的變數 i;

現在修改以上程式碼,把using指示寫在main函式內部,為了容易做實驗,就寫在了main內部第一個引用變數 i 的語句後邊:

#include <iostream>
#include "named_namespace.h"

using namespace std;
int i = 200; //全域性變數;
int main()
{
  cout << "i=" << i << endl; //在此語句之前,只有一個全域性變數 i 可見,呼叫的是全域性變數i,即 int i = 200,如果此處要使用name_17_2_3的成員,必須以name_17_2_3進行限定;
  using namespace name_17_2_3;
  cout << "i=" << i << endl; //呼叫哪一個 i 呢?經過using指示後,從此處指示點開始,name_17_2_3的所有成員可見,就會有一個main之前定義的全域性變數 i, 和一個被using指示引入的變數 i,所以使用 i 會產生歧義;
  return 0;
}

b:從上述例子可以看出,只有在using指示點以後,name_17_2_3的所有成員名字才可見,才可以不帶名稱空間名字使用成員名字,那麼 ”usin指示的最近作用域“ 中的作用域指的就是:”從using指示點開始,直到包含using指示的作用域的末尾“ 這樣的一個作用域;

總結:以上兩種情況,不管將using指示寫在main內部還是外部,都將把name_17_2_3的所有成員引入全域性作用域,因為name_17_2_3被#include指令插入到了全域性作用域,相當於在全域性作用域定義它,雖然如此,只有在using指示點以後才能夠以短格式即不帶限定符使用這些成員;