在c++中,名稱(name)可以是符號常量、變量、函數、結構、枚舉、類和對象等等。工程越大,名稱互相沖突性的可能性越大。另外使用多個廠商的類庫時,也可能導致名稱沖突。為了避免,在大規模程序的設計中,以及在程序員使用各種各樣的C++庫時,這些標識符的命名發生沖突,標准C++引入關鍵字namespace(命名空間/名字空間/名稱空間),可以更好地控制標識符的作用域。
創建一個命名空間:
namespace A{ int a = 10; } namespace B{ int a = 20; } void test(){ cout << "A::a : " << A::a << endl; cout << "B::a : " << B::a << endl; }
命名空間只能全局范圍內定義(以下錯誤寫法)
void test(){ namespace A{ int a = 10; } namespace B{ int a = 20; } cout << "A::a : " << A::a << endl; cout << "B::a : " << B::a << endl; }
命名空間可嵌套命名空間
namespace A{ int a = 10; namespace B{ int a = 20; } } void test(){ cout << "A::a : " << A::a << endl; cout << "A::B::a : " << A::B::a << endl; }
命名空間是開放的,即可以隨時把新的成員加入已有的命名空間中
namespace A{ int a = 10; } namespace A{ void func(){ cout << "hello namespace!" << endl; } } void test(){ cout << "A::a : " << A::a << endl; A::func(); }
聲明和實現可分離
#pragma once namespace MySpace{ void func1(); void func2(int param); }
void MySpace::func1(){ cout << "MySpace::func1" << endl; } void MySpace::func2(int param){ cout << "MySpace::func2 : " << param << endl; }
無名命名空間,意味着命名空間中的標識符只能在本文件內訪問,相當於給這個標識符加上了static,使得其可以作為內部連接
namespace{ int a = 10; void func(){ cout << "hello namespace" << endl; } } void test(){ cout << "a : " << a << endl; func(); }
命名空間別名
namespace veryLongName{ int a = 10; void func(){ cout << "hello namespace" << endl; } } void test(){ namespace shortName = veryLongName; cout << "veryLongName::a : " << shortName::a << endl; veryLongName::func(); shortName::func(); }
------------------------------------------------------------------------------------------------------------------------------------------------------------
using聲明
using聲明可使得指定的標識符可用。
namespace A{ int paramA = 20; int paramB = 30; void funcA(){ cout << "hello funcA" << endl; } void funcB(){ cout << "hello funcA" << endl; } } void test(){ //1. 通過命名空間域運算符 cout << A::paramA << endl; A::funcA(); //2. using聲明 using A::paramA; using A::funcA; cout << paramA << endl; //cout << paramB << endl; //不可直接訪問 funcA(); //3. 同名沖突 //int paramA = 20; //相同作用域注意同名沖突 }
using聲明碰到函數重載
如果命名空間包含一組用相同名字重載的函數,using聲明就聲明了這個重載函數的所有集合。
1 namespace A{ 2 void func(){} 3 void func(int x){} 4 int func(int x,int y){return x+y;} 5 } 6 void test(){ 7 using A::func; 8 func(); 9 func(10); 10 func(10, 20); 11 }
--------------------------------------------------------------------------------------------------------------
using編譯指令
using編譯指令使整個命名空間標識符可用.
注意:使用using聲明或using編譯指令會增加命名沖突的可能性。也就是說,如果有名稱空間,並在代碼中使用作用域解析運算符,則不會出現二義性。
namespace A{ int paramA = 20; int paramB = 30; void funcA(){ cout << "hello funcA" << endl; } void funcB(){ cout << "hello funcB" << endl; } } void test01(){ using namespace A; cout << paramA << endl; cout << paramB << endl; funcA(); funcB(); //不會產生二義性 int paramA = 30; cout << paramA << endl; } namespace B{ int paramA = 20; int paramB = 30; void funcA(){ cout << "hello funcA" << endl; } void funcB(){ cout << "hello funcB" << endl; } } void test02(){ using namespace A; using namespace B; //二義性產生,不知道調用A還是B的paramA //cout << paramA << endl; }
命名空間使用
需要記住的關鍵問題是當引入一個全局的using編譯指令時,就為該文件打開了該命名空間,它不會影響任何其他的文件,所以可以在每一個實現文件中調整對命名空間的控制。
比如,如果發現某一個實現文件中有太多的using指令而產生的命名沖突,就要對該文件做個簡單的改變,通過明確的限定或者using聲明來消除名字沖突,這樣不需要修改其他的實現文件。