### 定义和使用命名空间

在一个应用程序的多个文件中可能会存在同名的全局对象，这样会导致应用程序的链接错误。使用命名空间是消除命名冲突的最佳方式。

命名空间的定义格式为：

namespace 名称

{

常量、变量、函数等对象的定义

}

例如，下面的代码定义了两个命名空间。其程序代码如下：

namespace Output //定义一个命名空间 Output

{

const int MAXLEN = 128; //定义一个常量

int ivar = 10; //定义一个整型变量

void PutoutText(const char* pchData) //定义一个输出函数

{

if (pchData != NULL) //判断指针是否为空

{

printf("PutoutText 命名空间：%s\n",pchData); //输出数据

}

}

}

namespace Windows //定义一个命名空间 Windows

{

typedef unsigned int UINT; //自定义一个类型

void PutoutText(const char* pchData) //定义一个输出函数

{

if (pchData != NULL) //判断指针是否为空

{

printf("Windows 命名空间: %s\n",pchData); //输出数据

}

}

}

如果使用命名空间中的对象，需要在对象前使用命名空间名作为前缀。例如，下面的函数调用将是非法的。

PutoutText("Welcome to CHINA!");

而应使用命名空间作为前缀。上述代码应修改为：

Output::PutoutText("Welcome to CHINA!");

如果需要访问同一个命名空间中的多个对象，可以使用 using 命令引用整个命名空间对象，这样就不必在每个对象前添加命名空间前缀了。例如：

using namespace Output; //引用命名空间

PutoutText("Welcome to CHINA!"); //访问 Output 命名空间中的函数

using 命名的作用域从当前引用处到当前作用域的结束。如果将 using 命名放置在复合语句中，在复合语句结束时，using 名的作用域也结束了。例如，下面的函数调用是非法的，因为 using 命令的作用域已经结束了。

int main(int argc, char* argv[])

{

{ /复合语句

using namespace Output; //引用命名空间

}

PutoutText("Welcome to CHINA!"); //非法的函数访问

return 0;

}

如果在函数中定义的局部变量与命名空间中的变量同名时，命名空间中的变量被隐藏。例如：

int main(int argc, char* argv[])

{

int ivar = 5; //定义一个局部变量

using namespace Output; //使用 Output 命名空间

PutoutText("Welcome to CHINA!"); //访问命名空间中的 PutoutText 函数

printf("%d\n",ivar); //ivar 的值为 5

printf("%d\n",Output::ivar); //ivar 的值为 10

return 0;

}

上述代码中局部变量 ivar 隐藏了命名空间 Output 中的变量，因此第一个 printf 函数输出的值为 5，为了访问被隐藏的 Output 命名空间中的变量 ivar，需要使用命名空间作为前缀，例如“Output::ivar”，尽管前文已经使用 using 命令引用命名空间 Output。

如果程序中使用了 using 命令同时引用了多个命名空间，并且命名空间中存在相同的函数，将导致歧义，出现编译错误。例如：

int main(int argc, char* argv[])

{

using namespace Output; //引用 Output 命名空间

using namespace Windows; //引用 Windows 命名空间

PutoutText("Welcome to CHINA!"); //产生歧义，两个命名空间中均出现了 PutoutText 函数

return 0;

}

解决的方式是必须使用具体命名空间进行区分。例如：

Windows::PutoutText("Welcome to CHINA!");

对于同一个命名空间，可以在多个文件中定义。此时，各个文件中的对象将处于同一个命名空间中。例如，在 main.cpp 头文件中定义了一个命名空间 Output。

示例，在多个文件中定义命名空间。

namespace Output //定义一个命名空间 Output

{

const int MAXLEN = 128; //定义一个常量

int ivar = 10; //定义一个整型变量

void PutoutText(const char* pchData) //定义一个输出函数

{

if (pchData != NULL) //判断指针是否为空

{

printf("PutoutText 命名空间：%s\n",pchData); //输出数据

}

}

}

在 login.cpp 头文件中还可以定义 Output 命名空间。例如：

namespace Output //定义一个命名空间 Output

{

void Demo() //定义一个函数

{

printf("This is a function!\n");

}

}

此时，命名空间 Output 中的内容为两个文件 Output 命名空间内容的“总和”。因此，如果在 login.cpp 文件的 Output 命名空间中定义一个整型变量 ivar 是非法的，因为它与 main.cpp 文件中 Output 命名空间中的变量同名。

在定义命名空间时，通常在头文件中声明命名空间中的函数，在源文件中定义命名空间中的函数。将程序的声明与实现分开。例如，在头文件中声明命名空间函数。

namespace Output

{

void Demo(); //声明函数

}

在源文件中定义函数。

void Output::Demo() //定义函数

{

printf("This is a function!\n");

}

在源文件中定义函数时，注意要使用命名空间名作为前缀，表明实现的是命名空间中定义的函数。否则将是定义一个全局函数。

类似于复合语句，命名空间也可以嵌套。

例如，下面的代码定义了一个嵌套的命名空间。其程序代码如下：

namespace Windows //定义一个命名空间 Windows

{

typedef unsigned int UINT; //自定义一个类型

int ivar = 10;

void PutoutText(const char* pchData) //定义一个输出函数

{

if (pchData != NULL) //判断指针是否为空

{

printf("Windows 命名空间: %s\n",pchData); //输出数据

}

}

namespace GDI //定义一个嵌套的命名空间

{

int ivar = 5; //定义一个整型变量

void WriteText(const char* pchMsg) //定义一个函数

{

printf("%s\n",pchMsg); //输出信息

}

}

}

上述代码中，在 Windows 命名空间中又定义了一个命名空间 GDI，如果程序中访问 GDI 命名空间中的对象，可以使用外层的命名空间和内层的命名空间作为前缀。例如：

Windows::GDI::WriteText("2008"); //调用 GDI 命名空间中的函数

用户也可以直接使用 using 命令引用嵌套的 GDI 命名空间。例如：

using namespace Windows::GDI; //引用嵌套的 GDI 命名空间

WriteText("2008"); //调用 GDI 命名空间中的函数

上述代码中“using namespace Windows::GDI;”语句只是引用了嵌套在 Windows 命名空间中的 GDI 命名空间，并没有引用 Windows 命名空间。因此试图访问 Windows 命名空间中定义的对象是非法的。例如：

using namespace Windows::GDI;

PutoutText("Beijing"); //错误的访问，无法访问 Windows 命名空间中的方法

在使用 namespace 关键字定义命名空间时，也可以不指定命名空间的名称，此时的命名空间称之为未命名的命名空间。

例如，定义未命名的命名空间

namespace //定义一个未命名的命名空间

{

typedef unsigned int UINT; //自定义一个类型

int ivar = 10;

void PutoutText(const char* pchData) //定义一个输出函数

{

if (pchData != NULL) //判断指针是否为空

{

printf("未命名空间: %s\n",pchData); //输出数据

}

}

}

对于未命名的命名空间来说，其最大特点就是其命名空间中的对象只适用于当前文件，各个文件之间并不能相互访问定义在各自未命名空间中的对象。这一特点使得未命名空间中的对象与全局静态（static）对象（对于全局静态对象来说，只属于半个全局对象，它只能在当前文件中使用）所起的作用相同。多数 C++编译器都支持命名空间，使得越来越多的开发程序更愿意使用未命名的命名空间来代替全局静态对象。对于未命名的命名空间来说，访问其中定义的对象与访问普通的全局对象是相同的。例如：

PutoutText("Beijing"); //访问未命名空间中的对象

在定义未命名的命名对象时，注意其中的对象不能与全局对象同名或相同（函数可以重名，表示函数重载，但是参数列表不能完全相同）。例如，下面的代码是非法的。

namespace //定义一个未命名空间

{

typedef unsigned int UINT; //自定义一个类型

int ivar = 10;

void PutoutText(const char* pchData) //定义一个输出函数

{

if (pchData != NULL) //判断指针是否为空

{

printf("Windows 命名空间: %s\n",pchData); //输出数据

}

}

}

void PutoutText(const char* pchMsg)

{

if (pchData != NULL) //判断指针是否为空

{

printf("全局函数: %s\n",pchMsg); //输出数据

}

}

上述代码中全局函数 PutoutText 与未命名空间中的 PutoutText 函数声明格式（函数原型）相同，导致编译器产生了歧义。

说明：如果将未命名空间定义为有名称的命名空间（例如，namespace windows），则不会出现错误。