C++中的名字空间和作用域
C++程序支持四种形式的作用域,分别是:
①:名字空间作用域
②:局部作用域
③:类作用域
④:语句作用域
名字空间作用域:就是程序员利用名字空间定义在C++程序中划分出来的一块比较大的程序区段。在该程序区段内部,可以定义类型,函数,模版,变量。名字空间作用域可以跨越多个*.cpp文件而存在。在名字空间作用域内部还可以继续定义其他的名字空间作用域,也就是说,名字空间作用域是可以互相嵌套的。
全局作用域是:C++程序最外层的名字空间作用域,也是最大的名字空间作用域。全局作用域天然存在于C++程序中,它不需要由程序员人为地定义。在全局作用域内部,可以包含其他的,由程序员定义的名字空间作用域,以及没有包含在其他名字空间作用域中的类型,函数,模版,变量。在全局作用域中定义的变量是全局变量,在全局作用域中定义的函数是全局函数。
类作用域:在C++程序中,每定义一个类就会引入一个类域。类体所包含的范围就是类域的范围,在类中定义的所有成员都属于该类域。类域位于名字空间作用域内部,该名字空间作用域可能是全局作用域,也可能是用户定义的名字空间作用域。
语句作用域:每一个函数体内部都是一个局部作用域。该作用域起始于函数体的左花括号“{”,结束于函数体的右花括号“}”。每一个函数都有一个独立的局部作用域。在局部作用域内定义的变量都是局部变量。
在C++程序中,当要求使用单个语句,但程序逻辑却需要不止一个单个语句的时候,我们可以使用复合语句。复合语句通常被称为块,是用花括号括起来的一些单个语句的集合。在复合语句花括号内部的区段也属于局部作用域。
全局作用域,名字空间作用域,类作用域,局部作用域,语句作用域之间的关系如下图所示:
从上图可以看出,在全局作用域中,定义了两个名字空间W和S。名字空间W又分别位于两个CPP文件A和B中。由此可见,名字空间作用域是可以跨越CPP文件的。在名字空间S中,除了定义了类型外,又定义了一个名字空间E,所以说,名字空间之间是可以互相嵌套的。另外,在名字空间中可以定义类,函数,变量,模版等。
在全局作用域中,除了定义的名字空间W和S外,又定义了一个类D,以及全局函数,全局变量和模版。在类D中,定义了一些成员函数,因此引出了局部作用域。在局部作用域中,如果存在控制语句,就会存在语句作用域。
作用域生命周期:在各种作用域中定义的变量或对象,其生命周期从该变量被定义开始,直到该作用域结束。如:在全局作用域中定义的变量,其生命周期是整个程序的生命周期,程序运行结束,该变量被释放;在局部作用域中定义的变量,其生命周期是从定义该变量开始,直到该函数执行完毕。
问题:在C++中我们可以通过关键字namespace自定义名字空间,为的就是避免同名变量重定义,比如一个工程中有很多.cpp文件,其中一个.cpp文件让小A完成,另外一个.cpp文件让小B完成。结果这两个人都定义了一个叫tmp的全局变量,这个时候当工程链接的时候就会报错。原因是两个tmp有同样的名字空间,都是位于第4种名字空间中,也有着同样的作用域,都是文件作用域,于是这两个conan就冲突了。
怎么解决呢?
答:因为在同一个名字空间中的同一作用域下,相同的名字才会冲突。所以要解决冲突无非就是修改名字空间或者作用域。
我们一般不会修改变量作用域,所以一般就修改名字空间,这在C语言中是不允许的,因为C语言不可以自定义名字空间,但是在C++中是允许的。
于是小A将他的int tmp;写成了:
namespace xiao_A
{
int tmp = 10;
}
小B将他的int tmp;写成了:
namespace xiao_B
{
int tmp = 20;
}
这样小A的tmp就在名字空间xiao_A中了,而小B的tmp就在名字空间xiao_B中了,就不冲突了。
我们可以总结出C++中名字空间的作用:
①:用来解决名字冲突
②:作用域符(::)的使用
- global scope(全局作用域符),用法(::name)
- class scope(类作用域符),用法(class::name)
- namespace scope(命名空间作用域符),用法(namespace::name)
③:using 声明
using namespace 指示符
④:名字空间重名 =》合并
接下来我们可以验证一下以上的结论:
而我们要调用名字空间为CY1202中的sum函数,有以下几种方法:
①:使用using声明
②:使用using namespace指示符
③:使用命名空间作用域符,用法(namespace::name)
④:同名空间作用域 会进行合并
可以看到,两个CY1202名字空间进行了合并,在main函数中调用时,将a,c,sum全部显示了出来。