1、背景
为了解决名字冲突问题,人们提出了许多方法,例如:将实体名字写得长一些(包含十几个或者几十个字母和字符);把名字起得特殊一些,包括一些特殊的字符;由编译系统提供的内部全局标识符都用下划线作为前缀,如_complex(),以避免与用户命名的实体同名;由软件开发商提供的实体的名字用特定的字符作为前缀等,例如:海思的IPC方案中,定义的API名字:HI_xx。但是这些方法的会降低可读性。
2、什么是命名空间?
命名空间 namespace,是ANSI(American national standards institute,美国国家标准学会)C++ 引入的可以由用户命名的作用域,用来处理程序中常见的同名冲突(即在同一个作用域中有两个或者多个同名的实体)
3、命名空间的定义
(1)、程序设计者可以根据需要指定一些有名字的空间域,把一些全局实体分别放在各个命名空间中,从而与其他全局实体分隔开来。这有名字的空间域就是命名空间。命名空间的定义,例如:
namespace ns1 { int a; double b; const int c = 0.08; double tax() { return xxx; } class A { int a; double fun() { printf("helloworld\n"); } }; namespace ns2 {int a;} }
在声明一个命名空间时,花括号内不仅可以包括变量,而且还可以包括以下类型:
注意:命名空间不能包含预处理指令
变量(可以带有初始化)
常量
函数(可以是定义或者声明)
结构体
类
模板
命名空间(在一个命名空间中又定义一个命名空间,即嵌套的命名空间)
每个命名空间代表一个不同的命名空间域,不同的命名空间不能同名。命名空间的定义和类不一样,类在花括号的右括号外多一个 ";"
注意:在命名空间中定义或者声明的变量、结构体等都是全局的,仅仅是把它们隐藏在命名空间而已。如果在程序中要用到命名空间中的变量或者函数,类等等,那么有以下 3 种使用方法:
//假如命名空间ace中定义了一个Mutex类 //方法一: //用using一次性声明命名空间中所有成员 using namespace ace; //一次性声明指定命名空间里面的所有变量函数等 // Mutex mutex; //方法二: ace::Mutex mutex; //用到一个声明一个 //方法三: using ace::Mutex; //告诉编译器此后,如果在using作用域范围,那么就在命名空间 ace 中寻找 Mutex(这样的 using 语句只能声明命名空间中的一个成员)
Mutex mutex;
注意:mutex 是 ace::Mutex 定义的一个对象,但是 mutex 并不在命名空间 ace 中,所以不能通过 ace::mutex. 来调用 Mutex类中成员,而是直接mutex. 来调用。
#include <iostream> #include <string> using namespace std; namespace st { void fun1(void) { cout << "111\n" << endl; } } void fun1(void) { cout << "222\n" << endl; } int main(int argc, char **argv) { fun1(); //输出 222 using st::fun1; //告诉编译器此后,如果在st所用域范围,那么就在std中寻找fun1 fun1(); //输出 111 return 0; }
(2)、在使用了 "using" 语句来声明过命名空间后(例如,上面地方法一,方法三),在using的作用域范围内,如果using声明之后的地方要使用命名空间中的该成员时,则可以不必再逐个用命名空间限定(但并不是说这个空间中的其他成员不用指明命名空间)。例如:
using ace::Mutex; //这样的 using 语句只能声明命名空间中的一个成员 Mutex mutex; …… …… Student stud1(101, "wang", 18);//假如Student是命名空间ace中定义的类,这条语句是错误的
ace::Student stud1(101, "wang", 18);//这条才是对的
注意:using 声明的有效范围是从 using 开始到 using 所在的作用域结束
//其实上面的第二条语句
Mutex mutex;
//隐含的指定了命名空间,也就是相当于下面这条语句
ace::Mutex mutex;
但是,在同一作用域中使用 using 声明的不同命名空间的成员中不能有同名的成员。例如:
using ns1::Student; //声明其后出现的Student是命名空间ns1中的Student using ns2::Student; //声明其后出现的Student是命名空间ns2中的Student Student stud1; //请问此处的 Student 是哪个命名空间中的
(3)、如果命名空间的名字过长,或者嵌套命名空间过多,则会导致使用命名空间中的成员时,指定的命名空间名过长而繁琐,则我们可以使用命名空间的别名来表示原来的命名空间,例如:
namespace Television {……} namespace TV = Television;//TV是Television的别名,它们是等价的,可以在任何Television的位置无条件地用TV来代替
//那么下面两条语句是等价的
using namespace Television;
using namespace TV;
(4)、不连续的命名空间
命名空间可以定义在几个不同的部分中,因此命名空间是由几个单独定义的部分组成的。一个命名空间的各个组成部分可以分散在多个文件中。
所以,如果命名空间中的某个组成部分需要请求定义在另一个文件中的名称,则仍然需要声明该名称。下面的命名空间定义可以是定义一个新的命名空间,也可以是为已有的命名空间增加新的元素:
namespace namespace_name { // 代码声明 }
4、默认命名空间
默认命名空间,又叫全局命名空间,过去我们用的全局变量、函数 可以理解为存在于全局命名空间中,独立于所有有名的命名空间之外,它不需要 namespace 来声明的,实际上是由系统隐式声明的,在该空间中有效。
默认命名空间就是没有放在特定命名空间里面的,C++中只有唯一的一个,就是main函数
int main(void) { func3(); return 0; }
main函数必须放在默认命名空间里面的,不能放在特定命名空间里面的
(1)、默认命名空间又叫全局命名空间
(2)、默认命名空间里面引用其他命名空间的方法,就是上面提到的三种引用方法,
(3)、默认命名空间引用自己的方法,与C语言的函数引用没什么区别
(1)、其他命名空间引用默认命名空间的方法,::函数名();
void func5(void); //函数的声明要放在引用它的命名空间之前,因为编译只会往前回顾,不会往后看的。
namespace NS1 { void func2(void) { ::func5(); //表示func5定义和声明在默认命名空间,因为命名空间的名字是空的,所以冒号的前面是空的, // 也可以省略双冒号,最好加上,不加的话给人的感觉func5()是NS1里面的 //func1(); //如果是特定的命名空间内部访问自己的东西,前面什么都不用加 } void func1(void) { } }; //namespace NS2{void func3(void);}; namespace NS2{extern void func3(void);}; using namespace NS2; int main(void) { func3(); return 0; }
void func5(void)
{
}
5、匿名命名空间
参考博客:
https://www.cnblogs.com/youxin/p/4308364.html
当定义一个命名空间时,可以忽略这个命名空间的名称:
namespce { char c; int i; double d; }
编译器在内部会为这个命名空间生成一个唯一的名字,而且还会为这个匿名的命名空间生成一条using指令。所以上面的代码在效果上等同于:
namespace __UNIQUE_NAME_ { char c; int i; double d; }
using namespace __UNIQUE_NAME_;
在匿名命名空间中声明的名称也将被编译器转换,与编译器为这个匿名命名空间生成的唯一内部名称(即这里的__UNIQUE_NAME_)绑定在一起。匿名命名空间,在有的资料中又称 无名命名空间
还有一点很重要,就是这些名称具有internal链接属性,这和声明为static的全局名称的链接属性是相同的,即名称的作用域被限制在当前文件中,无法通过在另外的文件中使用extern声明来进行链接。如果不提倡使用全局static声明一个名称拥有internal链接属性,则匿名命名空间可以作为一种更好的达到相同效果的方法。
使用匿名空间比使用static至少有两个好处:
1) 对于一组多个标识符函数只需要使用一个匿名空间来声明,不需要多次输入static。
2) 可以嵌套。这样可以在不同命名空间中使用多个同名的标识符。
在C++的标准中也建议使用匿名命名空间间定义编译单元内部的全局变量,替代static,static关键词在此处被认为是过期的(deprecated)特性。
namespace { int a; void func() {……}; } int main() { a = 9; func(); return 0; }
(2)、在定义匿名空间的源文件中,可以在匿名空间的成员前加"::"来使用例如:
namespace { int a = 9; void func() {……}; } int a = 3; int main() { cout << ::a << endl; //9 ::func(); return 0; }
// 例程[2-5] #include <iostream> using namespace std; namespace{ int i = 256; } namespace ns{ namespace { int i = 128; } void func(void) { cout<<"ns::func :" <<endl; cout<<"\t::i="<<::i<<endl; //::i=256 cout<<"\tns::i="<<i<<endl; //ns::i=128 } } int main(void ) { cout<<::i<<endl; //256 cout<<"i="<<i<<endl; //i=256 cout<<"ns::i="<<ns::i<<endl; ns::func(); return 0; }
原文:https://www.cnblogs.com/xz-954042850-qq/p/13760657.html