曲径通幽论坛

标题: 名字空间简介(namespace) [打印本页]

作者: beyes    时间: 2011-12-7 11:06
标题: 名字空间简介(namespace)
名字空间机制是为了解决名字冲突而建立的。比如在程序中定义了一个名为 toupper() 的函数,那么这个函数会覆盖标准库函数中的 toupper() (假设两个函数的参数都相同),这是因为它们的名字都在全局名字空间中。

如果同一个程序中使用了两个或多个第三方库,名字冲突将变得更为复杂。此时,很可能发生在一个库中定义的名字和另一个库中具有同样的名字而冲突的情况。

namespace 关键字的目的就是为了解决上述的名字冲突问题。在名字空间中声明的名字只在局部作用域内可见,所以通过名字空间,我们可以在不同的程序上下文中使用同样的名字而不引起冲突。在 namespace 出现之前,整个 C++ 库都定义在全局名字空间之中(唯一的名字空间),而在其后,C++ 库则是定义在 std 这个名字空间中,这样在很大程度上减少了名字冲突的可能性。我们也可以在程序中年自定义自己的名字空间,将我们认为可能会造成冲突的名字定义在该名字空间中,这样,这些名字只会在局部的作用域中可见,从而避免了名字冲突。

使用 namespace 关键字创建声明区域,并以此来划分全局名字空间。从本质上来说,一个 namespace 定义了一个作用域,其通用形式如下:
namespace namem {
   //声明
}
所有在 namespace 中定义的元素都将被限定在这个名字空间的作用域内。

测试代码
[C++] 纯文本查看 复制代码
// namespace.cpp : 定义控制台应用程序的入口点。
//


#include "stdafx.h"
#include <iostream>
using namespace std;


//声明自己的名字空间
namespace CounterNameSpace {
    int upperbound;
    int lowerbound;


    class counter {
        int count;
    public:
        counter(int n)
        {
            if (n <= upperbound)
                count = n;
            else
                count = upperbound;
        }


        void reset(int n)
        {
            if (n <= upperbound)
                count = n;
        }


        int run()     //在名字空间中,函数可以直接使用空间中定义的变量lowerbound
        {
            if (count > lowerbound)
                return count--;
            else
                return lowerbound;
        }
    };
}




int _tmain(int argc, _TCHAR* argv[])
{
    CounterNameSpace::upperbound = 100;    //名字空间外的代码访问名字空间内的成员时需要在成员名前加上作用域解析运算符(::)
    CounterNameSpace::lowerbound = 0;


    CounterNameSpace::counter ob1(10);
    int i;


    do {
        i = ob1.run();    //声明了counter类型对象后,就无需再次限定对象成员的作用域(这里直接调用 ob1.run()),因为编译器已经知道了对象所在的作用域
        cout << i << " ";
    }while ( i > CounterNameSpace::lowerbound);


    cout << endl;


    CounterNameSpace::counter ob2(20);
    do {
        i = ob2.run();
        cout << i << " ";
    } while ( i > CounterNameSpace::lowerbound);
    cout << endl;


    ob2.reset(100);
    CounterNameSpace::lowerbound = 90;
    do {
        i = ob2.run();
        cout << i << " ";
    }while (i > CounterNameSpace::lowerbound);


    return 0;
}

运行输出:
10 9 8 7 6 5 4 3 2 1 0
20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
100 99 98 97 96 95 94 93 92 91 90

此外,同一个名字可以用来声明若干个名字空间。这样一个名字空间就被分散到几个文件,甚至是在同一个文件中,比如:
namespace NS {
   int i;
}
//...
namespace NS {
  int j;
}
上面,名字空间 NS 被划分为两部分。但是每个部分中的内容仍然是在同一个名字空间中的(这里是 NS)。

需要注意的是,必须在其他类型作用域之外声明名字空间,而且也不能在函数中声明一个名字空间。但是一个名字空间可以嵌入到另一个空间之中。
作者: beyes    时间: 2011-12-7 16:43
标题: 匿名名字空间
匿名名字空间是一种特殊的名字空间,它允许你在文件中创建惟一的名字空间标识符,声明一个匿名名字空间的通用形式如下:
namespace {
    //声明部分
}
匿名名字空间中的成员只有u在定义它们的文件中是可见的。也就是说,在包含匿名名字空间的文件中,可以直接用名字空间的成员而不需要限定符,但在文件作用域外,这些成员都是不可见的

static 与 匿名名字空间
如果在一个文件中用 static int 声明了一个全局变量,那么该全局变量的作用域将被限制在该文件中。这时如果在另一个文件中使用 external 来声明该变量,当链接这两个文件时,仍然会产生一个错误,如再 VC 中会提示“无法解析的外部符号”。

尽管 C++ 仍然允许在全局成员的声明中使用 static ,但是将一个标识符限定在某个文件作用域内的一个更好方法正是使用你名空间。比如:

在 file1.cpp 中
[C++] 纯文本查看 复制代码

namespace {
  int k;
}
void func1() {
  k = 100;  //正确
}

在 file2.cpp 中:
[C++] 纯文本查看 复制代码

extern int k;
void func2() {
  k = 101;   //错误
}

上面,k 被限定在 file1.cpp 这个文件中,所以在 fiel2.cpp 中看不见这个变量 k 。

标准 C++ 推荐在新的代码中使用匿名空间而不是用 static 来将全局成员限定在某个文件作用域内




欢迎光临 曲径通幽论坛 (http://www.groad.net/bbs/) Powered by Discuz! X3.2