namespace深入研究

1.为什么会出现namespace

主要原因:如果两个公司想要互相交流代码,使用的是c语言,会产生代码量复杂冗余的情况

//google公司的某变量
int Google_class1_Liu number;
//虎牙公司的某变量
int Huya_class1_Liu number;

由此可知,这样导致的结果是,为了防止变量重复多出来了一堆不必要的前缀名,因此,C++就有了namespace这一概念

2.常见的namespace

using namespace std;

与iostream模板密不可分,std命名空间内存在cin,cout,scanf,printf,endl等变量或者函数

3.如何定义一个自己的namespace

(1).像函数一样可以直接定义

namespace wd
{
int num = 1;
void print()
{
cout<<"print()"<<endl;
}
}

(2)也可以定义匿名空间

namespace
{
int num;
int a;
}

匿名空间所定义的变量或函数可以直接使用,不需要作用域限定符

(3)更可以像函数或者循环一样嵌套定义

namespace wd
{
int num;
namespace lr
{
int num;
}
}

其中::被称为作用域限定符

3.对namespace的一些操作

(1)使用已定义好的命名空间

namespace wd
{
int num;
}

int main()
{
cout<<wd::num<<endl;
return 0;
}

(2)使用自带的命名空间
(1)方法一

#include <iostream>

//using namespace std;
using std::cin;
using std::cout;
using std::endl;

int main()
{
int a;

cin>>a;
cout<<a<<endl;

return 0;
}

(2)方法二

#include <iostream>

//using namespace std;

int main()
{
int a;

cin>>a;
cout<<a<<endl;

return 0;

(3)方法三

#include <iostream>

int main()
{
int a;

std::cin>>a;
std::cout<<a<<std::endl;

return 0;

三种方法各有各的好处,方法二一般是刚入门或者是为了方便而直接使用整个命名空间,这样调用会直接把命名空间内的所有实体全部调出来,方法一和方法三是单独调用命名空间内的某个实体,虽然复杂一些但也降低了占用空间

如果想用stl内的容器,也是可以直接调用的,比如调用vector就写using std::vector,vector所具有的函数也是同时调用出来了

4.命名空间与函数上的一些联系

就像函数可以先声明再定义一样(可以声明多次但只能定义一次),命名空间内部的函数也可以先声明再定义,这使得命名空间就像容器一样可以无限定义实体

namespace wd
{
void print();
}

int main()
{
return 0;
}

namespace wd
{
void print()
{
cout<<"print()"<<endl;
}
}

总结及注意事项

1.细心的你应该注意到了,命名空间和我们日常编程的习惯不一样,是不允许缩进的(当然你想缩进也没啥大的影响),可能你会觉得这样会降低可读性,实则相反,因为namespace是专为大型项目而出现的,当代码量足够大,命名空间内足足上万个代码时,他的可读性反而很不错
2.匿名空间所定义的变量无法跨模块调用,即一个项目内某个源文件内定义的匿名空间内的一个变量无法被另一个源文件所调用,与c语言的static有异曲同工之处
源文件1

#include <iostream>

using std::cin;
using std::cout;
using std::endl;

extern int num;
extern int cnt;
int main()
{
cout<<num<<endl;
cout<<cnt<<endl;

return 0;
}

源文件2

int num;
namespace
{
int cnt;
}

如果将这两项代码放在一个项目内,你会发现编译无法通过,这是因为源文件2里cnt属于匿名空间,无法跨模块调用,如果删去cnt的调用及他的输出,代码就成功编译了
3.为了防止我们所定义的变量或函数与std内部的实体重复,建议非必要不去写using namespace std,而是去调用内部的某个实体
4.一种特殊情况:实体三重名

int num = 1;
namespace wd
{
int num = 2;
void print(int num)
{
cout<<num<<endl;
}
}

int main()
{
wd::print(3);
}

此时输出的结果是3,输出的是形参,如果不选择传参,输出的则是命名空间内部的实体2,再其次就是全局变量1

如果我们想让三个num都能输出

int num = 1;
namespace wd
{
int num = 2;
void print(int num)
{
cout<< ::num<<endl;//全局变量就是一种另类的匿名空间实体
cout<<wd::num<<endl;
cout<<num<<endl;
}
}

此时输出1 2 3

由此可以得知命名空间内部的函数对重名实体的操作是就近原则,有重名的就去使用最近的重名实体,通过作用域限定符可以避免该情况的发生