C++ 命名空间
命名空间用于解决合作开发时的名字冲突问题。
1、namespace
关键字
用于定义命名空间。
//定义命名空间
namespace name{
//variables, functions, classes
}
//使用命名空间内的成员
name::成员名;
name
是命名空间的名字,它里面可以包含变量、函数、类、typedef、#define 等。
::
是作用域运算符,在C++中用来指明要使用的命名空间。
-
只能在全局范围内定义,不能在函数内部定义。
-
命名空间可嵌套定义(一个
namespace
嵌套一个namespace
,使用时连续使用作用域解析符::
) -
如果include了
using
了某个命名空间的其他文件到当前文件,则using
的效果会被传播到当前文件。 -
如果将一个命名空间拆分到多个文件中来写,则如下:
// name.h namespace A{ extern int x; void func(); } // name.cpp namespace A{ int x = 2; void func(){std::cout<<"haha";} }
-
命名空间是开放的,即可以随时把新的成员加入已有的命名空间中
namespace A{ int a = 10; namespace B{ int b = 11; } } namespace A{//往A中加入一个func void func(){ cout << "hello namespace!" << endl; } } void test(){ cout << "A::a : " << A::a << endl; cout << "A::B::b :" << A::B::b << endl; A::func(); }
-
命名空间内的成员声明和定义可以分离(命名空间体内声明函数签名,命名空间外用
::
定义) -
无名命名空间:无名命名空间中的标识符只能在本文件内访问,相当于给这个标识符加上了
static
,使得其可以作为内部连接namespace{ int a = 10; void func(){ cout << "hello namespace" << endl; } }
-
全局命名空间:定义变量、函数或其他标识符时,如果没有放置在任何命名空间中,则属于全局命名空间。全局命名空间中的标识符可以被整个程序中的任何地方访问。使用
::
来强制使用全局命名空间:// 全局命名空间 int x = 5; // 一个普通命名空间 namespace MyNamespace { int x = 10; } int main() { // 使用全局命名空间中的x std::cout << "Global x: " << ::x << std::endl; // 使用普通命名空间中的x std::cout << "Namespace x: " << MyNamespace::x << std::endl; }
-
命名空间可以起别名
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(); }
关于嵌套命名空间的补充
1.什么是嵌套命名空间?
嵌套命名空间就是在命名空间里面在定义其它的命名空间,就像是俄罗斯套娃。
namespace np1 {
namespace np2 {
namespace np3 {}
} // namespace np2
...
} // namespace np1
2.实验
2.1 外部引用嵌套命名空间内的符号
情况一
#include <iostream>
using namespace std;
namespace np1 {
namespace np2 {
void func2() {
cout << "np1::np2::func2" << endl;
}
} // namespace np2
void func1() {
cout << "np1::func1" << endl;
}
} // namespace np1
int main() {
np1::func1();
np1::np2::func2();
return 0;
}
实验结果:
表明嵌套命名空间的引用是符合namespace语法的,没有特殊之处。
情况二
using namespace np1;
int main() {
func1();
np2::func2();
return 0;
}
输出结果一样。
2.2 命名空间内容不同层次间符号的引用
情况一:第一层调用第二层
#include <iostream>
using namespace std;
namespace np1 {
namespace np2 {
void func2() {
cout << "np1::np2::func2" << endl;
}
} // namespace np2
void func1() {
np2::func2();
}
} // namespace np1
int main() {
np1::func1();
return 0;
}
实验结果:
表明在命名空间内部的不同层次符号引用依然遵循namespace语法。
情况二:第二层调用第一层
#include <iostream>
using namespace std;
namespace np1 {
void func1() {
cout << "np1::func1" << endl;
}
namespace np2 {
void func2() {
func1(); // np1::func1();
}
} // namespace np2
} // namespace np1
int main() {
np1::np2::func2();
return 0;
}
实验结果:
表明np1相对于np2来说,是默认命名空间。
情况三:第二层调用第一层,但是第一层和第二层存在相同的符号
#include <iostream>
using namespace std;
namespace np1 {
void func1() {
cout << "np1::func1" << endl;
}
namespace np2 {
void func1() {
cout << "np1::np2::func1" << endl;
}
void func2() {
func1();
}
} // namespace np2
} // namespace np1
int main() {
np1::np2::func2();
return 0;
}
实验结果:
表明np2优先会调用自己内部的符号。正如一个函数的内部,它会优先调用自己的局部变量,接着才考虑寻找外部变量。
2、using
关键字
用于声明命名空间中的单个成员或声明整个命名空间,使得指定的标识符可用。
//声明单个成员
using name::成员名;
//声明整个命名空间
using namespace name;
(1)一个cpp文件里可以使用多个using
语句。
using namespace A;
using namespace B;
如果编译器发现某个名字在多个缺省的名字空间都出现过,会显示编译错误,这时就必须使用::
操作符强行指定名字空间了。
例如你自己定义了一个变量,名字也叫cout
。这时你就必须指定是std::cout
还是::cout
(2)using声明碰到函数重载:如果命名空间包含一组用相同名字重载的函数,using声明就声明了这个重载函数的所有集合。
namespace A{
void func(){}
void func(int x){}
int func(int x,int y){}
}
void test(){
using A::func;
//所有的func均可用
func();
func(10);
func(10, 20);
}