名字空间

✍ dations ◷ 2024-12-24 02:00:25 #名字空间

名字空间(英语:Namespace),也称命名空间、名称空间等,它表示着一个标识符(identifier)的可见范围。一个标识符可在多个名字空间中定义,它在不同名字空间中的含义是互不相干的。这样,在一个新的名字空间中可定义任何标识符,它们不会与任何已有的标识符发生冲突,因为已有的定义都处于其他名字空间中。

例如,设Bill是X公司的员工,工号为123,而John是Y公司的员工,工号也是123。由于两人在不同的公司工作,可以使用相同的工号来标识而不会造成混乱,这里每个公司就表示一个独立的名字空间。如果两人在同一家公司工作,其工号就不能相同了,否则在支付工资时便会发生混乱。

这一特点是使用名字空间的主要理由。在大型的计算机程序或文档中,往往会出现数百或数千个标识符。名字空间提供一隐藏区域标识符的机制。通过将逻辑上相关的标识符组织成相应的名字空间,可使整个系统更加模块化。

在编程语言中,名字空间是对作用域的一种特殊的抽象,它包含了处于该作用域内的标识符,且本身也用一个标识符来表示,这样便将一系列在逻辑上相关的标识符用一个标识符组织了起来。许多现代编程语言都支持名字空间。在一些编程语言(例如C++和Python)中,名字空间本身的标识符也属于一个外层的名字空间,也即名字空间可以嵌套,构成一个名字空间树,树根则是无名的全局名字空间。

函数和类的作用域可被视作隐式名字空间,它们和可见性、可访问性和对象生命周期不可分割的联系在一起。

在C++语言中,名字空间是一种实体(entity),使用namespace来声明,并使用{ }来界定名字空间体(namespace body)。

例:

namespace foo {    int bar;}

C语言的全局作用域对应于C++全局名字空间作用域。全局名字空间不需要声明也无法显式声明。使用时,可以用前缀为::的qualified-id显式限定全局名字空间作用域中的名称。例如,::operator new指称全局new运算符函数。

名字空间可以在另一名字空间之中嵌套声明;但不能声明在类和代码块之中。在名字空间中声明的名称,默认具有外部链接属性(除非声明的是const对象,它默认是具有内部链接属性)。

按照是否有名字,可分为有名字的名字空间、不能显式定义的全局名字空间与匿名名字空间。后者的声明为:

namespace {    // namespace-body(即声明序列(可选))}

匿名名字空间中的名字具有文件作用域。这些名字在本编译单元中可以直接使用;也可以用前缀为::的qualified-id显式限定后使用。匿名名字空间中的名字具有内部链接属性。

名字空间的成员,是在名字空间体的花括号内声明了的名字。可以在名字空间体之外,给出名字空间成员的定义。即名字空间的成员声明与定义可以分开。名字空间内的名字,只能有一次定义,但可以多次声明。

嵌套的子名字空间必须定义在上层名字空间体之内。禁止把子名字空间的声明与定义分开。

不能以“名字空间名::成员名;”方式,在名字空间体之外为名字空间添加新成员。必须在名字空间体之中添加新成员的声明。

可以多次声明和定义同一名字空间,每次给这一名字空间添加新成员。同名的名字空间即便在声明位置不同,仍然是同一个实体。

可以在一个名字空间中引入其他名字空间的成员。例如:

namespace myNameSpace{    using namespace His_NameSpace;    using OLib::List;    void my_func(String &, List &);}

引用名字空间的成员,有下述办法:

名字空间可以有别名:namespace 别名 = 命名空间名; 这使得名字较长的名字空间可以方便地用较短的别名来引用。


C++11起支持内联名字空间。使用inline namespace作为声明的起始。内联名字空间的名称在名称查找时被特别对待,使用qualified-id引用其中的名称时,被内联的名字空间名称可以省略。也即,内联名字空间内的标识符被提升到包含着内联的名字空间的那个父级的名字空间中。内联名字空间可以在修改名字空间名称的同时避免在二进制文件中生成的符号改变,因此不同内联名字空间的名称可以用于标识接口兼容的不同版本,有助于保持二进制兼容性。这也在标准库的实现中被使用,如libstdc++和libc++。

namespace Contoso{    namespace v_10    {        template <typename T>        class Funcs        {        public:            Funcs(void);            T Add(T a, T b);            T Subtract(T a, T b);            T Multiply(T a, T b);            T Divide(T a, T b);        };    }    inline namespace v_20    {        template <typename T>        class Funcs        {        public:            Funcs(void);            T Add(T a, T b);            T Subtract(T a, T b);            T Multiply(T a, T b);            std::vector<double> Log(double);            T Accumulate(std::vector<T> nums);      };    }}

在XML中的应用

XML虽然不是一个独立的编程语言,但是它的出现使得名字空间的使用变得更为广泛。

在同一个名字空间里,所有的元素名都必须唯一。

声明一个名字空间使用XML保留的属性xmlns,它的值必须是URI(统一资源标志符 Uniform Resource Identifier而非URL--Universal Resource Locator)指代.比如xmlns="http://www.w3.org/1999/xhtml".注意,事实上URI是不可读的,但它对XML解析器来说就只是简单不过的字符串,如http://www.w3.org/1999/xhtml/(页面存档备份,存于互联网档案馆) 这个地址本身并不包含任何代码,它只表示XHTML名字空间.使用URI (比如"http://www.w3.org/1999/xhtml")去标示一个名字空间,而不是用一个简短的字符串 (比如"xhtml"),这样做是为了减少不同名字空间标示符冲突的可能性.

相关