转载:https://www.cnblogs.com/zhoug2020/p/5972439.html
一, 为什么需要命名空间(问题提出)
命名空间是ANSIC++引入的可以由用户命名的作用域,用来处理程序中 常见的同名冲突.
在 C 语言 中定义了 3 个层次的作用域,即文件 (编译单元),函数和复合语句.C++ 又引入了类作用域,类是出现在文件内的.在不同的作用域中可以定义相同名字的变量,互不于扰,系统能够区别它们.
1,全局变量的作用域是整个程序,在同一作用域中不应有两个或多个同名的实体(enuty),包括变量,函数和类等.
例:如果在文件中定义了两个类,在这两个类中可以有同名的函数.在引用时,为了区别,应该加上类名作为限定:
class A // 声明 A 类
{ public:
void funl();// 声明 A 类中的 funl 函数
private:
int i; };
void A::funl() // 定义 A 类中的 funl 函数
{............}
class B //声明B类
{ public:
void funl(); //B类中也有funl函数
void fun2(); };
void B::funl() //定义B类中的funl函数
{ ............}
这样不会发生混淆.
在 文件中可以定义全局变量 (global variable),它的作用域是整个程序.如果在文件 A 中定义了一个变量 a int a=3;
在文件 B 中可以再定义一个变量 a int a=5;
在分别对文件 A 和文件 B 进行编译时不会有问题.但是,如果一个程序包括文件 A 和文件 B,那么在进行连接时,会报告出错,因为在同一个程序中有两个同名的变量,认为是对变量的重复定义.
可 以通过 extern 声明同一程序中的两个文件中的同名变量是同一个变量.如果在文件 B 中有以下声明:
extem int a;
表示文件 B 中的变量 a 是在其他文件中已定义的变量.由于有此声明,在程序编译和连接后,文件 A 的变量 a 的作用域扩展到了文件 B.如果在文件 B 中不再对 a 赋值,则在文件 B 中用以下语句输出的是文件 A 中变量 a 的值: cout<
二, 什么是命名空间(解 决方案)
命名空间:实际上就是一个由程序设计者命名的内存区域,程序设计者可以根据需要指定一些有名字的空间域,把一些全局实体分别放在各个命名空间中,从而与其他全局实体分隔开来.
如: namespace ns1 // 指定命名中间 nsl
{ int a;
double b; }
namespace 是定义命名空间所必须写的关键字,nsl 是用户自己指定的命名空间的名字 (可 以用任意的合法标识符,这里用 ns1 是因为 ns 是 namespace 的缩写,含义请楚),在花括号内是声明块,在其中声明的实体称为命名空间成员(namespace member).现在命名空间成员包括变量 a 和 b,注意 a 和 b 仍然是全局变量,仅仅是把它们隐藏在指定的命名空间中而已.如果在程序中要使用变量 a 和 b,必须加上命名空间名和作用域分辨符 "::",如 nsl::a,nsl::b.这种用法称为命名空间限定(qualified),这些名字(如 nsl::a) 称为被限定名 (qualified name).C++ 中命名空间的作用类似于 操作系统 中的目录和文件的关系,由于文件很多,不便管理,而且容易重名,于是人们设立若干子目录,把文件分别放到不同的子目录中,不同子目录中的文件可以同名.调用文件时应指出文件路径.
命名空间的作用:是建立一些互相分隔的作用域,把一些全局实体分隔开来.以免产生老点名叫李相国时,3 个人都站起来应答,这就是名字冲突,因为他们无法辨别老师想叫的是哪一个李相国,同名者无法互相区分.为了避免同名混淆,学校把 3 个同名的学生分在 3 个班.这样,在小班点名叫李相国时,只会有一个人应答.也就是说,在该班的范围 (即班作用域) 内名字是惟一的.如果在全校集合时校长点名,需要在全校范围内找这个学生,就需要考虑作用域问题.如果校长叫李相国,全校学生中又会有 3 人一齐喊 "到",因为在同一作用域中存在 3 个同名学生.为了在全校范围内区分这 3 名学生,校长必须在名字前加上班号,如高三甲班的李相国,或高三乙班的李相国,即加上班名限定.这样就不致产生混淆.
可以根据需要设置许多个命名空间,每个命名空间名代表一个不同的命名空间域,不同的命名空间不能同名.这样,可以把不同的库中的实体放到不同的命名空间中,或者说,用不同的命名空间把不同的实体隐蔽起来.过去我们用的全局变量可以理解为全局命名空间,独立于所有有名的命名空间之外,它是不需要用 namespace 声明的,实际上是由系统隐式声明的,存在于每个程序之中.
在声明一个命名空间时,花括号内不仅可以包括变量,而且还可以包括以下类型:
. 变量 (可以带有初始化);
. 常量;
. 数 (可以是定义或声明);
. 结构体;
. 类;
. 模板;
. 命名空间 (在一个命名空间中又定义一个命名空间,即嵌套的命名空间).
例如
namespace nsl
{ const int RATE=0.08; // 常量
doublepay; // 变量
doubletax() // 函数
{return a*RATE;}
namespacens2 // 嵌套的命名空间
{int age;}
}
如果想输出命名空间 nsl 中成员的数据,可以采用下面的方法:
cout<
三, 使用命名空间解决名字冲突(使用指南)
有了以上的基础后,就可以利用命名空间来解决名字冲突问题.现在,对例 4 程序进行修改,使之能正确运行.
例 5 利用命名空间来解决例 4 程序名字冲突问题.
修改两个头文件,把在头文件中声明的类分别放在两个不同的命名空间中.
// 例 8.5 中的头文件 1,文件名为 header1.h
using namespace std;
#include
#include
namespace ns1 // 声明命名空间 ns1
{ class Student // 在命名空间 nsl 内声明 Student 类
{ public:
Student(int n,string nam,int a)
{num=n;name=nam;age=a;}
void get_data();
private:
int num;
string name;
int age; };
void Student::get_data() // 定义成员函数
{ cout<
四, 使用命名空间成员的方法
从上面的介绍可以知道,在引用命名空间成员时,要用命名空间名和作用域分辨符对命名空间成员进行限定,以区别不同的命名空间中的同名标识符.即:
命名空间名::命名空间成员名
这种方法是有效的,能保证所引用的实体有惟一的名字.但是如果命名空间名字比较长,尤其在有命名空间嵌套的情况下,为引用一个实体,需要写很长的名字.在一个程序中可能要多次引用命名空间成员,就会感到很不方便.
1 ,使用命名空间别名
可以为命名空间起一个别名 (namespace alias),用来代替较长的命名空间名.如
namespace Television // 声明命名空间,名为 Television
{...}
可以用一个较短而易记的别名代替它.如:
namespace TV=Television; // 别名 TV 与原名 Television 等价
也可以说,别名 TV 指向原名 Television,在原来出现 Television 的位置都可以无条件地用 TV 来代替.
2,使用 using 命名空间成员名
using 后面的命名空间成员名必须是由命名空间限定的名字.例如:
using nsl::Student;
以上语句声明:在本作用域 (using 语句所在的作用域) 中会用到命名空间 ns1 中的成员 Student,在本作用域中如果使用该命名空间成员时,不必再用命名空间限定.例如在用上面的 using 声明后,在其后程序中出现的 Student 就是隐含地指 nsl::Student.
using 声明的有效范围是从 using 语句开始到 using 所在的作用域结束.如果在以上的 using 语句之后有以下语句:
Student studl(101,"Wang",18); // 此处的 Student 相当于 ns1::Student
上面的语句相当于
nsl::Student studl(101,"Wang",18);
又如
using nsl::fun; // 声明其后出现的 fun 是属于命名空间 nsl 中的 fun
cout<
五, 无名的命名空间
以上介绍的是有名字的命名空间,C++ 还允许使用没有名字的命名空间,如在文件 A 中声明了以下的无名命名空间:
namespace // 命名空间没有名字
{void fun() // 定 义命名空间成员
{cout<<"OK."<
六,标准命名空间 std
为了解决 C++ 标准库中的标识符与程序中的全局标识符之间以及不同库中的标识符之间的同名冲突,应该将不同库的标识符在不同的命名空间中定义 (或声明).标准 C++ 库的所有的标识符都是在一个名为 std 的命名空间中定义的,或者说标准头文件(如 iostream) 中函数,类,对象和类模板是在命名空间 std 中定义的.std 是 standard(标准)的缩写,表示这是存放标准库的有关内容的命名空间,含义请楚,不必死记.
这样,在程序中用到 C++ 标准库时,需要使用 std 作为限定.如
std::cout<<"OK."<
七, 使用早期的函数库
C 语言程序中各种功能基本上都是由函数来实现的,在 C 语言的发展过程中建立了功能丰富的函数库,C++ 从 C 语言继承了这份宝贵的财富.在 C++ 程序中可以使用 C 语言的函数库.
如果要用函数库中的函数,就必须在程序文件中包含有关的头文件,在不同的头文件中,包含了不同的函数的声明.
在 C++ 中使用这些 头文件有两种方法.
1,用 C 语言的传统方法
头文件名包括后缀.h,如 stdio.h,math.h 等.由于 C 语言没有命名空间,头文件并不存放在命名空间中,因此在 C++ 程序文件中如果用到带后缀.h 的头文件时,不必用命名空间.只需在文件中包含所用的头文件即可.如
#include
2,用 C++ 的新方法
C++ 标准要求系统提供的头文件不包括后缀.h,例如 iostream,string.为了表示与 C 语言的头文件有联系又有区别,C++ 所用的头文件名是在 C 语言的相应的头文件名 (但不包括后缀.h) 之前加一字母 c.例如,C 语言中有关输入与输出的头文件名为 stdio.h 在 C++ 中相应的头文件名为 cstdio.C 语言中的头文件 math.h,在 C++ 中相应的头文什名为 cmath.C 语言中的头文件 string.h 在 C++ 中相应的头文件名为 cstring.注意在 C++ 中,头文件 cstnng 和头文件 strmg 不是同一个文件.前者提供 C 语言中对字符串处理的有关函数 (如 strcmp,ctrcpy) 的声明,后者提供 C++ 中对字符串处理的新功能.
此外,由于这些函数都是在命名空间 std 中声明的,因此在程序中要对命名空间 std 作声明.如:
#include
#include
using namespace std;
目前所用的大多数 C++ 编译系统既保留了 c 的用法,又提供丁 C++ 的新方法.下面两种用法等价,可以任选.
C 传 统方法 C++ 新方法
#include #include
#include #include
#include #include
using namespace std;
可以使用传统的 c 方法,但应当提倡使用 C++ 的新方法.
来源: http://www.bubuko.com/infodetail-2475265.html