浅谈namespace与using
zybnxy
·
·
个人记录
0:一些前言
不知你们有没有发现这个语句
using namespace std;
他是干嘛用的?
我们我们一开始只是把这句活当成背子背上,却无法真正理解它的含义,其实,这包括了两个C++中的关键字using 和namespace,其中using从字面上就可以知道它是引用的意思,那么namespace和using是什么?
1:namespace用法
在程序中,我们可以根据需要设置许多个命名空间,每个命名空间名代表一个不同的命名空间域,不同的命名空间不能同名。这样,可以把不同的库中的实体放到不同的命名空间中,或者说,用不同的命名空间把不同的实体隐蔽起来。过去我们用的全局变量可以理解为全局命名空间,独立于所有有名的命名空间之外,它是不需要用 $namespace$声明的,实际上是由系统隐式声明的,存在于每个程序之中。
```cpp
#include<iostream>
#include<algorithm>
namespace zyb//开了一个名为zyb的名字命名空间
{
int swap(int &a,int &b)
{
int t=a;a=b;b=t;
}
}
int main()
{
int a=3,b=4;
zyb::swap(a,b);//调用zyb中的swap函数
std::cout<<a<<' '<<b<<std::endl;
std::swap(a,b);//调用标准库中的swap函数
std::cout<<a<<' '<<b<<std::endl;
}
```
运行结果:

我们发现,这个程序的主函数中调用了两次$swap$函数,只不过一个函数是$algorithm$自带的,另一个函数是写在我们自己开的名字空间$zyb$中,所以它们互不冲突。
c++的函数库中的函数都是写在一个名叫$std$的名字命名空间中的,事实上,我们每次从系统库中调用一个函数,我们都需要在函数名前写上
```
std::xxx();
```
例如
```cpp
std::cin>>n;
std::sort(a,a+n);
std::memset(x,x,sizeof(x);
```
等
当然,如果要调用自己写的$namespace$,只需要把$std$改成$\text{你自己的名字}$就可以了
$P.S.$:如果你懒得这么麻烦,你还是用
```cpp
using namespace xxx;
```
好了
但是,我们发现。
这TMD跟直接写函数有什么区别。
我:~~当然有区别了,你需要加xxx::调用它啊~~
#### 首先,$namespace$真正的作用是避免处理程序中常见的同名冲突,比如上边举的例子,代码中同时出现了两次$swap$,正常情况中会使代码调不出来,但是当我们用了一个$namespace$之后就不存在这个问题,其次,在程序中还往往需要引用一些库(包括C++编译系统提供的库、由软件开发商提供的库或者用户自己开发的库),为此需要包含有关的头文件。如果在这些库中包含有与程序的全局实体同名的实体,或者不同的库中有相同的实体名,则在编译时就会出现名字冲突。人们首先想出的方法是取一个好几位,甚至十几位的变量名,但是这样即不利于调试代码,也不利于代码的编写,于是就出现了$namespace$,$namespace$的出现,也是彻底解决了这个问题。
总结的来说,$namespace$就是有避免重复出现函数名的过程。
## 2:$using$的作用
$namespace$有一个缺陷,我们也不难发现,就是在调用期中的函数非常麻烦,
比如:
```cpp
#include <iostream>
int main()
{
int a,b;
std::cin>>a>>b;
std::cout<<a+b;
return 0;
}
```
我们发现,$namespace$虽然有好处,但是这样会使码量增加,使代码可读性降低。这个问题如何解决呢?
我们用$using$就可以解决这个问题
### 使用$using$ $namespace$来命名空间名
在我们的代码中,我们的这一句
```cpp
using namespace std;
```
就是用$using$ $namesopace$来命名$std$这个空间名,这样,当我们调用$std$中的函数时,就不用加那些烦人的东西了,当然,$std$是系统自带的空间名,当然,我们也可以用这样的方式,来命名我们的空间名
例如LZ自己写的LJ读入/输出模板
```cpp
namespace read
{
#define LL long long
#define ULL unsigned long long
inline int Iread()
{
char ch;
int flag=1,res=0;
ch=getchar();
for(;!isdigit(ch);ch=getchar())
if(ch=='-')flag=-1;
for(;isdigit(ch);ch=getchar())
res=res*10+(ch-'0');
return flag*res;
}
inline LL Lread()
{
char ch;
LL flag=1,res=0;
ch=getchar();
for(;!isdigit(ch);ch=getchar())
if(ch=='-')flag=-1;
for(;isdigit(ch);ch=getchar())
res=res*10+(ch-'0');
return flag*res;
}
inline double Fread()
{
double r;
double x=0,t=0;int s=0,f=1;char c=getchar();
for(;!isdigit(c);c=getchar())
{
if (c=='-') f=-1;
if (c=='.') goto readt;
}
for (;isdigit(c)&&c!='.';c=getchar()) x=x*10+c-'0';
readt:for (;c=='.';c=getchar());
for (;isdigit(c);c=getchar()) t=t*10+c-'0',++s;
r=(x+t/pow(10,s))*f;
return r;
}
inline void Sread1(char s[])
{
char ch;
for(register int i=0;;i++)
{
ch=getchar();
if(ch=='\n')break;
s[i]=ch;
}
}
inline void Sread2(char s[])
{
char ch;
for(register int i=0;;i++)
{
ch=getchar();
if(ch==' ')break;
s[i]=ch;
}
}
inline int Iout(int x)
{
if(x<0)
{
putchar('-');x=-x;
}
if(x>9)Iout(x/10);
putchar(x%10+'0');
}
inline LL Lout(LL x)
{
if(x<0)
{
putchar('-');x=-x;
}
if(x>9)Iout(x/10);
putchar(x%10+'0');
}
inline void Sout(char s[])
{
for(register int i=0;i<strlen(s);i++)
putchar(s[i]);
}
inline void Fout(double x,int k)
{
static ULL n=pow(10,k);
if (x==0)
{
putchar('0'),putchar('.');
for (int i=1;i<=k;++i) putchar('0');
return;
}
if (x<0) putchar('-'),x=-x;
LL y=(LL)(x*n)%n;x=(LL)x;
Lout(x),putchar('.');
int bit[100],p=0,i;
for (;p<k;y/=10) bit[++p]=y%10;
for (i=p;i>0;i--) putchar(bit[i]+48);
}
}
```
不用数了,这其中一共有$9$个函数名,如果遇到了一些输入量很大的题目,这样敲代码一定会浪费很多的时间
所以,我们只需要在下边写上这一句
```cpp
using namespace read;
```
我们就可以直接调用了这个函数了。
$for$ $example$:
```cpp
int a;
long long b;
char c[100];
double d;
a=Iread();Iout(a);putchar('\n');//整形读入输出
b=Lread();Lout(b);putchar('\n');//长整型读入输出
Sread1(c);Sout(c);putchar('\n');//字符串读入输出,遇到\n停止
Sread2(c);Sout(c);putchar('\n');//同上,遇到' '停止 *
d=Fread();Fout(d,18);putchar('\n');//浮点型输入输出,保留最多18位小数
```
这样就可以让你免受$read::$的骚扰。
## 总结:本文介绍了平时常用的$namespace$与$using$的用法,希望这会对大家有帮助
> $By: 2018.10.17