前言

常用。

1
using namespace std;

std就是一个命名空间。

当然最终感觉还是为了便于管理。

1
2
3
namespace hack{
int ....
}

把需要用到的函数和变量或者结构体之类的塞到一个命名空间中,这样下次调用起来就很方便:hack::...


正文

1
2
3
4
5
6
7
8
9
10
11
12
#include<iostream>

namespace hack{
int value;
}
using namespace hack;

int main(){
value = 200;

return 0;
}

这里因为解锁了hack空间,所以里面的变量可以直接调用,但是这样不好的事如果别处有同样定义的变量还是会冲突的。
这也是为什么大部分人其实一开始不会直接using namespace std;因为std里面有很多的变量啊之类的,就怕你词穷冲突了。解决的办法就是用到啥using一下:using std::cout;
良好的代码习惯固然重要,但是后期团队协作还是要看整体风格


全局命名空间

就是说具有链接或者外部属性的对象,只要不存在于定义的命名空间内,就默认定义在全局命名空间中。在全局命名空间中的访问不需要额外指定,除非局部的变量重复了,就需要用到全局命名空间指定。

1
2
3
4
5
6
7
8
int a;

int main(){
int a = 100;
::a = 200;

return 0;
}

能够看到两个a的值是不同的。

当然这个链接或外部属性是什么意思的,就是全局变量,且非静态的。
像main函数之内的int a;就是局部的,他就不会存在于全局命名空间。

::前面没东西就是全局


命名空间拓展

在标准头文件中<iostream>是最常使用的头文件,其中std命名空间自然在其中。
当引用其它头文件,比如<string>的时候,它也需要从std命名空间中使用。

1
2
3
4
5
6
7
8
#include<iostream>
#include<string>

int main(){
std::string str = "12334";

return 0;
}

这说明命名空间是可以拓展的,而且拓展的方法也很简单,在写一个namespace std的操作即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<iostream>
#include<string>

namespace hack{
int value;
}
using namespace hack;

int a;

namespace hack{
float height;
}

int main(){
//...
return 0;
}

可以看到分开写的命名空间hack各自有一个成员,但是调用的时候是统一的。


命名空间的声明

1
2
3
namespace hack{
int value;
}

对于变量,这种情况我们默认就当成定义了,因为即便没有初始化也有可能分配到一个垃圾值。或者被优化掉。
声明一个变量之前提到过加上extern

1
2
3
namespace hack{
extern int value;
}
1
2
3
4
5
6
#pragma once
extern int value;

void test(){
::value;
}

这样的value还是处于全局命名空间。

1
2
3
4
//main.cpp
#include"main.h"

int hack::value = 200;
1
2
3
4
5
//main.h
#pragma once
namespace hack{
extern int value;
}

照例输出一下:

并且函数也是同样的

1
2
3
4
5
#pragma once
namespace hack{
extern int value;
void test();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<iostream>
#include"main.h"

int a;
namespace hack{
float height=25.25;
}

int hack::value = 200;
void hack::test(){
std::cout << hack::height;
}

int main(){
hack::test();

return 0;
}

输出一下:

所以声明和定义选择上跟源文件和头文件、源文件和源文件之间的联系是一样的


命名空间的嵌套

函数能套娃,命名空间也能套娃

1
2
3
4
5
6
7
8
9
10
11
12
namespace hack{
float height=25.25;

namespace hackbar{
int hack_he;
}
}
int main(){
hack::hackbar::hack_he;

return 0;
}

多套几层也没啥事,反正能够通过::访问到。


未命名的命名空间

1
2
3
namespace {

}

未命名的命名空间中的声明一律为内部连接属性,包括用extern声明的内容,且未命名的命名空间只在本转换单元有效。

一个函数不能同时出现在多个源文件当中,因为在编译的时候会发生重复定义。
按照C语言当时的习惯就是使用static或者inline之类的,当然c++之后是不期望这么用的。

1
2
3
4
5
6
7
8
9
10
namespace{
void hhh(){
std::cout << "hhh\n";
}
}
int main(){
hhh();

return 0;
}
1
2
3
void hhh(){

}

这种情况下,hhh函数不会发生报错,因为它存在于未命名命名空间中,具有内部连接属性,跟外部不冲突。

而且即使不同源文件都出现:

1
2
3
4
5
namespace{
void hhh(){
std::cout << "hhh\n";
}
}

也不会像之前的命名空间会自然拓展,未命名命名空间是完全独立的。


命名空间别名

之前给结构体哪些创建别名都是通过typedef
命名空间有自己起别名的方式namespace a = xxx::xxx之类的

1
2
3
4
5
6
7
8
namespace hack{
float height=25.25;

namespace hackbar{
int hack_he;
}
}
namespace a = hack::hackbar;

那么下次调用hackbar的参数,就可以直接从a::hack_he了。


结语

c++特性,还是要好好了解的,毕竟后面还有类。