命名空间
一、命名空间的定义
1.命名空间的由来:一个大型的工程往往是由若干个人独立完成的,不同的人分别完成不同的部分,最后再组合成一个完整 的程序。由于各个头文件是由不同的人设计的,有可能在不同的头文件中用了相同的名字来命名所定义 的类或函数,这样在程序中就会出现名字冲突。不仅如此,有可能我们自己定义的名字会与C++库中的 名字发生冲突。 名字冲突就是在同一个作用域中有两个或多个同名的实体,为了解决命名冲突 ,C++中引入了命名空 间,所谓命名空间就是一个可以由用户自己定义的作用域,在不同的作用域中可以定义相同名字的变 量,互不干扰,系统能够区分它们。
2.命名空间的定义: 命名空间又称为名字空间,是程序员命名的内存区域,程序员根据需要指定一些有名字的空间域,把一 些全局实体分别存放到各个命名空间中,从而与其他全局实体分隔开。通俗的说,每个名字空间都是一 个名字空间域,存放在名字空间域中的全局实体只在本空间域内有效。名字空间对全局实体加以域的限 制,从而合理的解决命名冲突。
3.命名空间的基本格式
c++
namespace 命名空间的名字
{
定义的变量;
}
注意:大括号内不仅可以存放变量,还可以存放:变量、常量、函数(可以是定义或声明 )结构体、类、模板以及可以嵌套定义的命名空间。
代码案例
c++
namespace ff
{
int number = 100;
struct Foo
{
char ch;
int val;
};
void play();
}
定义在名称空间中的变量或者函数都称为实体,名称空间中的实体作用域是全局的, 并不意味着其可见域 是全局的。 如果不使用作用域限定符和using机制,抛开名称空间嵌套和内部屏蔽的情况,实体的可见域是从实体创建到该名称空间结束。 **在名称空间外,该实体是不可见的。**但我们需要使用命名空间的实体的时候,就需要特殊的使用方法
二、命名空间使用方法
命名空间一共有三种使用方式,分别是using编译指令、作用域限定符、using声明机制
1.using编译指令
使用using编译指令,就会把该命名空间中的所有实体一次性引入到程序之中,例如
C++
#include <iostream>
using namespace std
int main()
{
cout << "hell,world" << endl;
return 0;
}
我们最常见的就是使用 using namespace std;,这个代码的意思就是引入了std这个命名空间,std是标准库(Standard Library)我们所熟知的cout、cin等就是在这个命名空间里的。
2.using声明机制
如果全部使用该命名空间的所有实体,只用部分,则需要使用using::实体名来实现,例如:
c++
#include <iostream>
using std::cout;
using std::endl;
namespace wd
{
int number = 10;
void display()
{
cout << "wd::display()" << endl;
}
}
using wd::number;
using wd::display;
int main()
{
cout << "wd::number = " << number << endl;
wd::display();
}
在给定的代码中,using
关键字的作用域是从其声明位置开始直到当前作用域结束。具体来说,以下是using
声明的作用域:
using std::cout;
和using std::endl;
的作用域是整个文件(全局作用域),因为它们位于#include <iostream>
之后且在任何函数或命名空间定义之前。using wd::number;
和using wd::display;
的作用域是wd
命名空间内部和main()
函数内部。这是由于这两个using
声明位于namespace wd
和main()
函数之间。
在main()
函数中,可以直接使用number
和display
,而无需加上命名空间前缀wd::
。但是在其他命名空间或函数定义中,仍然需要使用完整的命名空间限定符才能访问wd
命名空间中的标识符。要注意,在同一作用域内用 using声明的不同的命名空间的成员不能有同名的成员,否则会发生重定义。
3.作用域限定符
第三种方式就是直接使用作用域限定符::。每次要使用某个名称空间中的实体时,都直接加上,例如:
c++
namespace dd
{
int number = 10;
void display()
{
std::cout << "wd::display()" << std::endl;//cout,endl都是std空间中的实体,所以都加上'std::'命名空间
}
}
int main()
{
std::cout << "wd::number = " << wd::number << endl;
wd::display();
}
但因为比较冗余,所以不经常用。
三.匿名命名空间
命名空间还可以不定义名字,不定义名字的命名空间称为匿名命名空间。由于没有名字,该空间中的实体,其它文件无法引用,它只能在本文件的作用域内有效,它的作用域是从匿名命名空间声明开始到本文件结束。在本文件使用无名命名空间成员时不必用命名空间限定。其实匿名命名空间和static是同样的道理,都是只在本文件内有效,无法被其它文件引用。
c++
#include <iostream>
using std::cout;
using std::endl;
int g_number2 = 10;
namespace
{
int number = 2;
void print()
{
cout << "hello,world" << endl;
}
}
使用匿名命名空间,直接调用其函数即可
c++
int main() {
// 调用匿名命名空间中的变量和函数
std::cout << "Number: " << number << std::endl;
print();
return 0;
}
同时,在C++中,static关键字有多重含义,其中之一就是用于限制变量或函数的作用域,使其仅在当前文件(或当前匿名空间)内可见。当我们在匿名空间中声明一个全局变量,并将其定义为static时,它的作用范围将被限制在该匿名空间内部。
由于该变量是全局变量,具有全局生存期,因此在程序的整个执行过程中都存在。然而,由于它的作用范围限制在匿名空间内部,外部的其他函数无法直接访问该变量。只有在同一匿名空间内的函数才能通过变量名来访问和操作这个static全局变量。
四.命名空间的跨模块调用
以上述代码为例子,改为非匿名命名空间,并且建立MyNameSpace.cpp文件
c++
#include <iostream>
using std::cout;
using std::endl;
int g_number2 = 10;
namespace SC
{
int number = 2;
void print() {
cout << "hello,world" << endl;
}
然后建立一个新的MyNameSpace1.cpp文件,列入以下代码
C++
#include <iostream>
#include "MyNameSpace.cpp"
// 引入命名空间
using namespace myNameSpace;
int main() {
// 调用命名空间中的函数
print();
return 0;
}
//或者不使用using,直接使用作用域限定符即可
SC::print();
即可完成对命名空间的跨模块调用
五.命名空间的嵌套和覆盖
C++
#include <iostream>
using namespace std;
int number = 1;
namespace wz
{
int number = 10;
namespace wh
{
int number = 100;
void display()
{
cout << "wz::wh::display()" << endl;
}
}
void display(int number)
{
cout << "形参number = " << number << endl;
cout << "wz命名空间中的number = " << wz::number << endl;
cout << "wh命名空间中的number = " << wz::wh::number << endl;
}
}
int main(void)
{
using wz::display;
display(1);
wz::wh::display();
return 0;
}
将会产生以下结果
c++
形参number = 1
wz命名空间中的number = 10
wh命名空间中的number = 100
wz::wh::display()
每一个步骤:
- 在全局作用域中定义了一个全局变量
number
,其值为1。 - 定义了命名空间
wz
,在其中定义了一个局部变量number
,其值为10。 - 在
wz
命名空间中定义了另一个命名空间wh
,在其中定义了一个局部变量number
,其值为100,并定义了函数display()
。 - 在
wz
命名空间中的display()
函数中,输出了形参number
的值,即10。 - 输出了
wz
命名空间中的number
变量的值,即1。 - 输出了
wz::wh
命名空间中的number
变量的值,即100。 - 调用了
wz::wh::display()
函数,输出了"wz::wh::display()"。
参考文献来自于王道的C++命名空间讲义,有删改。