c++之命名空间

C语言中所有变量都有自己的作用域,声明变量的类型不同,其作用域也不同。C语言中的变量,按照作用域的范围可分为两种, 即局部变量和全局变量,所对应的作用域为局部作用域和全局作用域。

简单来说:
局部作用域是指:在函数内作定义说明的。其作用域仅限于函数内, 离开该函数后再使用这种变量是非法的。

全局作用域:也称为外部变量,它是在函数外部定义的变量,可以在程序的任何地方访问。 它不属于哪一个函数,它属于一个源程序文件。其作用域是整个源程序。

在c++中,变量,函数和类都是大量存在的,如果这些变量,函数和类都是存在于全局命名空间内,会导致很多冲突,这时我们就引入了命名空间来解决这个问题。

使用命名空间的目的就是对标识符名称进行本地化,以避免命名冲突或名字污染,更好地控制标识符的作用域。

作用域与命名空间:

1.与命名空间相关的概念:

声明域(declaration region) —— 声明标识符的区域。

如:
在函数外面声明的全局变量,它的声明域为声明所在的文件。 
在函数内声明的局部变量,它的声明域为声明所在的代码块。

潜在作用域(potential scope)—— 从声明点开始,到声明域的末尾的区域。

因为C++采用的是先声明后使用的原则,所以在声明点之前的声明域中,标识符是不能用的。 
即,标识符的潜在作用域,一般会小于其声明域。

作用域(scope)—— 标识符对程序可见的范围。

标识符在其潜在作用域内,并非在任何地方都是可见的。 
例如,局部变量可以屏蔽全局变量、嵌套层次中的内层变量可以屏蔽外层变量,从而被屏蔽的全局或外层变量在其倍屏蔽的区域内是不可见的。  

所以,一个标识符的作用域可能小于其潜在作用域。 

2.命名空间:

命名空间(namespace)是一种描述逻辑分组的机制,可以将按某些标准在逻辑上属于同一个集团的声明放在同一个命名空间中。

原来C++标识符的作用域分成三级:代码块({……},如复合语句和函数体)、类和全局。现在,在其中的类和全局之间,标准C++又添加了命名空间这一个作用域级别。

命名空间可以是全局的,也可以位于另一个命名空间之中,但是不能位于类和代码块中。所以,在命名空间中声明的名称(标识符),默认具有外部链接特性(除非它引用了常量)。

在所有命名空间之外,还存在一个全局命名空间,它对应于文件级的声明域。因此,在命名空间机制中,原来的全局变量,现在被认为位于全局命名空间中。

标准C++库(不包括标准C库)中所包含的所有内容(包括常量、变量、结构、类和函数等)都被定义在命名空间std(standard标准)中了。

命名空间的定义:

定义命名空间就相当于定义了一个新的作用域,在这个命名空间结构中有函数或者(全局)变量。
命名空间的定义有两种形式:有名字的和无名字的。

有名的命名空间:

 格式: 
       namespace 命名空间名 
        {
               namespace-body
       }

例如:

    namespace N1
    {
        int a=10void Funtest()
        {
            printf(“N1::Funtest()\n”);
        }
    }

无名的命名空间:

 格式: 
       namespace  
       {
               namespace-body
       }

例如:

namespace
    {
        int f=10;
    }//没有名字的命名空间-相当于当前文件中的全局变量,他的成员只能在当前文件中使用,访问时不用加命名空间名称,对其他文件不可见

说明:

命名空间的成员,是在命名空间定义中的花括号内声明了的名称。

可以在命名空间的定义内,定义命名空间的成员(内部定义)。

也可以只在命名空间的定义内声明成员,而在命名空间的定义之外,定义命名空间的成员(外部定义)。

命名空间成员的外部定义的格式为:

命名空间名::成员名 ……

命名空间的特征:

(1)命名空间可以嵌套

namespace N2
{
    int a=40void Funtest()
    {
        printf(“N2::Funtest()\n”);
    }
    namespace N3
    {
        int a=50void Funtest()
        {
            printf(“N2::N3::Funtest()\n”);
        }
    }
}

(2)相同名字命名空间可以同时存在(前提是这两个空间中没有相同的变量或函数,否则会提示 “ambiguous symbol”的错误信息)-系统会把多个相同命名空间内容整合在一起

namespace N1
{
    int a=10void Funtest()
    {
        printf(“N1::Funtest()\n”);
    }
}
namespace N1
{
    int b=20;
}

命名空间的使用:

1.与命名空间使用相关的概念:

作用域解析运算符(::)

对命名空间中成员的引用,需要使用命名空间的作用域解析运算符'::'。 

using指令(using namespace)

为了省去每次调用Inner成员和标准库的函数和对象时,都要添加Outer::Inner::和sta::的麻烦,可以使用标准C++的using编译指令来简化对命名空间中的名称的使用。格式为:
        using namespace 命名空间名[::命名空间名……];

在这条语句之后,就可以直接使用该命名空间中的标识符,而不必写前面的命名空间定位部分。因为using指令,使所指定的整个命名空间中的所有成员都直接可用。 

using声明(using)

除了可以使用using编译指令(组合关键字using namespace)外,还可以使用using声明来简化对命名空间中的名称的使用。格式为:
        using 命名空间名::[命名空间名::……]成员名;

注意,关键字using后面并没有跟关键字namespace,而且最后必须为命名空间的成员名(而在using编译指令的最后,必须为命名空间名)。

与using指令不同的是,using声明只是把命名空间的特定成员的名称,添加该声明所在的区域中,使得该成员可以不需要采用,(多级)命名空间的作用域解析运算符来定位,而直接被使用。 
但是该命名空间的其他成员,仍然需要作用域解析运算符来定位。

2.使用命名空间

(1)直接加载命名空间

int main()
{
    N1::Functest();
    return 0;
}

(2)使用using声明—适用于使用命名空间内部少量内容

using N1::Functest();
int main()
{
    Functest();
    return 0;
}

(3)使用using指令将命名空间所有内容导入

using namespace N1;
int main()
{
    Functest();
    return 0;
}

命名空间的名称:

命名空间的别名:

标准C++引入命名空间,主要是为了避免成员的名称冲突。若果用户都给自己的命名空间取简短的名称,那么这些命名空间本身,也可能发生名称冲突。

如果为了避免冲突,而为命名空间取很长的名称,则使用起来就会不方便。这是一个典型的两难问题。

标准C++为此提供了一种解决方案——命名空间别名,格式为:

namespace 别名 = 命名空间名; 

另外,没有名字的命名空间与static修饰哪一种方式比较好?

当我们在使用static关键字时会有一些限制,如不适用于是类型定义。 而匿名的名字空间则没有这些问题。另一方面,static在不少地方被用到,而且含义各不相同,所以C++标准倾向于使用匿名名字空间。
详见链接
static vs unnamed namespace

猜你喜欢

转载自blog.csdn.net/tanrui519521/article/details/79936772
今日推荐