using namespace std;到底是在干嘛?

为什么要有namespace?

回答这个问题之前,我们先看一下这样一段C语言代码

#include <stdio.h>
int rand = 1;
int main()
{
	printf("%dn", rand);
	return 0;
}

没有学过C语言的同学,可以把这里的printf("%dn", rand),看成是c++的cout<<rand<<endl,<stdio.h>printf()的头文件。

毫无疑问,输出结果一定是1

那如果再加一个头文件呢?

#include<stdlib.h>
#include <stdio.h>
int rand = 1;
int main()
{
	printf("%dn", rand);
	return 0;
}

此时再运行,就会看到如下报错:

error C2365: “rand”: 重定义;以前的定义是“函数”

为什么rand重定义了?

<stdlib.h>内有一个C语言自己的库函数

image-20220427200440724

所以这里就同时存在了int rand;int rand(void)两个同名变量,从而报错。

像这里,跟库里的变量名冲突还好,报错了,我们大不了换个变量名,但公司里一个项目几十人、几百人,很难避免。

C++之所以建立,可以说就是为了解决一些C语言的不足,那堆大佬为了解决命名冲突的问题,就提出了命名空间的概念。

namespace怎么用?

要区分不同的域,我们就要为每个域都定义自己的名字,nemespace这个关键字就是这个作用。

定义语法

namespace N1
{
    //支持变量
    int a = 1;
    //支持函数
    int f()
    {
        return 1}
    //支持结构体/类
   	struct S
    {
        int _s;
    }
}

像这样,namespace,后面跟着命名空间的名字,然后接一对{}即可,{}中放命名空间的成员。

嵌套

命名空间是支持嵌套的。

namespace N2
{
    int a;
    int f();
    namespace N3
    {
        int b;
        
    }
    
}

同名融合

同一个工程中,允许存在多个相同名称的命名空间,编译器最后会把他们合成一个命名空间。

namespace N4
{
    int a;
}
namespace N4
{
    int b;
}

编译器处理之后就会变成这样:

namespace N4
{
    int a;
    int b;
}

所以说,这里的两个N4中当然也就不能有同名的变量了。

融合使命名空间可合并,嵌套又可避免合并之后产生内部冲突,这时把嵌套和融合两条规则加在,一起就可以实现如下操作:

一个公司,所有人都使用公司名、项目模块、个人名,的嵌套式空间命名方式,在合并之后可以避免命名冲突。

命名空间的使用

空间定义好了,那怎么使用呢?

#include<stdio.h>
namespace N 
{
	int a = 10;
	int b = 20;
}

int main()
{
	printf("%dn", a); // 该语句编译出错,无法识别a
	return 0; 
}

直接访问a肯定是不可以的,必须要有一种突破命名空间域的方式。

一般,根据不同情况,有三种方式可以使用。

方式1

使用using namespace 命名空间名称引入

就像我们平时我们用的那句using namespace std;

这里的std其实就是个命名空间标示符,C++标准库中的函数或者对象都是在命名空间std中定义的。

这里用了这句using namespace std;就相当于直接把它的命名空间的壳拆了,也就是可以直接访问里边的所有函数和对象,如cout、cin、endl……

#include<stdio.h>
namespace N 
{
	int a = 10;
	int b = 20;
}
using namespace N;
int main()
{
	printf("%dn", a); // 正常打印
	return 0; 
}

这里使用了using namespace N;将于域中的变量都释放于全局区,也就相当于俩全局变量(注:释放前也是全局变量,只不过受命名空间域的限制)

这种方式虽然最为方便,但危险性也是最高的,不管会不会用到,都会放出来,发生命名冲突的的可能性也更高。

方式2

使用using将命名空间中成员引入

有时我们写using namespace std;也只为了使用cincoutendl,所以我们不妨只将cincoutendl放出来,语法如下:

using std::cin;

using std::cout;

using std::endl;

方式1中的案例,同样也可以用此方法:

using N::b;
int main()
{
	printf("%dn", b);
	return 0; 
}

方式3

在使用方式3之前,我们要先看一下域作用限定符的概念:

域作用限定符

其实在c语言阶段其实就已经有这个符号了,而且也是用来解决变量名冲突问题的

#include<stdio.h>
int a = 0;
int main()
{
	int a = 1;
	printf("%dn",a);
	return 0;
}

这段代码会报错吗?

答案是不会,这里的两个a一个是全局变量,一个是局部变量,并不会发生访问冲突,再不做任何操作的条件下,会默认访问局部变量。

如果想访问全局域的那个a,只需要在前面加一个域作用限定符::(俩冒号)

#include <iostream>
using namespace std;
int a = 0;
int main()
{
	int a = 1;
    printf("访问局部变量(a):%dn",a);
	printf("访问全局变量(::a):%dn",::a);
	return 0;
}

这段代码的运行运行结果就是:

访问局部变量(a):1

访问全局变量(::a):0

在c++中

还是上面的代码,如果a前面啥也没有,默认访问局部变量;

前面加上::,访问全局变量;

那么在::前面再加一个命名空间名呢?

顺理成章的,第三种访问方式产生了

变量名前加命名空间名称::

#include <iostream>
using namespace std;
int main()
{
    cout << 1 << endl;
}

就可改成:

#include <iostream>
int main()
{
    std::cout << 1<< std::endl;
}

案例2:

#include<stdio.h>
namespace N 
{
	int a = 10;
	int b = 20;
}
int main()
{
	printf("%dn", N::a); // 正常打印
	return 0; 
}