在 C++ 中,命名空间(namespace)用来把类、函数、变量等标识符封装起来,避免命名冲突和名字污染------这是它最基础的作用。`using 声明` 和`using 指令` 到底差在哪、为什么头文件里不能用`using namespace std` 、从定义到嵌套、内联命名空间、别名一路讲下来,最后都落到这几个必考问题上。
命名空间里面是声明定义区域,不是执行代码的地方。
所以命名空间里面放各种声明和定义,不能放执行代码的
所以不同命名空间也算不同作用域
一、命名空间的特性
1.命名空间只能放全局函数外面,所以命名空间的成员都是全局变量
2.不同命名空间算不同作用域,所以即使都处于全局但也有不同作用域
3.命名空间里面可以放数据类型,函数声明和定义,结构体等等甚至放另一个命名空间
命名空间是什么?
定义一个命名空间格式是
namespace 命名空间名字
{
//声明定义变量 //命名空间里面的东西都算成员,只不过结构体成员没值,命名空间结构体可以有值
//函数声明和定义
//定义结构体/共用体/枚举 数据类型
//声明类 定义对象
//其他命名空间 //命名空间允许嵌套另一个命名空间
} //没有分号,结构体有分号
那么平时说的标准命名空间是什么?
是 using namespace std;
using是使用意思,namespace是命名空间意思,std是空间名
这里就不用再声明里面的东西了,因为这是C++标准库的命名空间
其余的命名空间要声明里面的东西,而标注命名空间不用
std是C++标准库的命名空间的空间名,意思是C++标准库里面的东西都放在std这个命名空间里面
cout、cin、string全部都装在std这个盒子里。
所以只要用了cout和cin就要写使用标准命名空间
当然自己定义其他空间名也行,但是标准库里面的东西只能放在std这个空间名里面C++写死了
using namespace std;意思是:打开 std 这个盒子,盒子里面东西直接拿出来用,不用写 std::
如果不写这个语句,那么后面代码的变量名要加空间名加域运算符::
空间名加域运算符::就是直接拿取空间名的成员
如
std::cout
域运算符有点像结构体,但是结构体只能放数据类型,而命名空间可以放很多东西
二、命名空间里面可以放什么东西?
命名空间里面是声明定义区域,不是执行代码的地方。
命名空间里面可以放:全局变量、函数、结构体、类、枚举、类型别名、嵌套命名空间。
不能放:预处理指令、局部变量。
命名空间主要放全局变量,函数声明和定义,类,结构体,还可以嵌套其他命名空间
命名空间不能放局部变量和可执行语句
匿名命名空间是什么
匿名结构体只无法间接定义结构体数据类型,匿名空间只是一个没有名字的空间,实际算有名字
匿名空间的语法格式
namespace
{
int val=100;
} //这就是一个匿名命名空间
匿名空间相当于命名空间没有空间名,没有空间名就用不了域运算符
所以他的成员的用法就不用写空间名加域运算符
如
#include
using namespace std;
namespace
{
int val=100;
}
int main()
{
cout
return 0;
}
三、匿名命名空间(无名命名空间)作用
匿名命名空间:namespace { ... },没有名字的命名空间
1.作用域限制:成员仅在当前源文件 (.cpp) 内可见,其他文件无法访问。
效果等价于static修饰全局变量 / 函数,实现文件内部私有。
2.本文件内部可以直接使用里面的成员,不需要写::作用域解析运算符。
3.避免全局名字冲突:把本文件内部要用的变量、函数放到匿名命名空间,不会和别的文件的全局名字发生冲突
匿名命名空间和全局变量的歧义性
命名空间也并非万能的,当匿名结构体和全局变量碰在一起会发生歧义,语法不通过
如
cpp
//====单独全局变量的时候语法格式========
#include<iostream>
using namespace std;
int val=100;
int main()
{ //如果局部没有同名变量,`main`里直接用就是全局的`val`。
cout<<"val的值是"<<val<<endl; //结果为100
return 0;
}
//====单独匿名结构体的时候语法格式======
#include<iostream>
using namespace std;
namespace
{
int val=300;
}
int main()
{
cout<<"val的值是"<<val<<endl; //结果为300
return 0;
}
会发现cout打印全局变量和打印匿名结构体成员的时候语法格式一样
当他们一起碰在一起发生歧义性语法不通过
//===全局变量和匿名结构体一起打印同一个成员==============
#include<iostream>
using namespace std;
namespace
{
int val=300;
}
int val=100;
int main()
{
cout<<"val的值是"<<val<<endl; //此时语法不通过无法编译
cout<<"val的值是"<<val<<endl;
return 0;
}
但是如果全局变量和匿名结构体和局部变量在一起
//===全局变量和匿名结构体和局部变量在一起打印同一个成员=====
#include<iostream>
using namespace std;
namespace
{
int val=300;
}
int val=100;
int main()
{
int val;
cout<<"val的值是"<<val<<endl;
cout<<"val的值是"<<val<<endl;
cout<<"val的值是"<<val<<endl;
return 0;
}
打印结果:
val的值是200
val的值是200
val的值是200
因为除了运算符有优先级,变量之间也有优先级,变量之间的优先级针对是不同作用域,同一个变量名在代码块里面
变量的优先级看代码块就近原则,看代码块离哪个变量近,哪个变量在代码块里面
局部变量在代码块里面,第一个val,局部变量优先级最高,打印200,但此时会触发一个机制,加做名字遮蔽机制
300、100 这两个变量内存里的值仍然保留不变,只是名字val被局部变量 "遮蔽(shadow)",访问不到它们,不是把它们的值改成 200。
就记住发生名字遮蔽后,代码块里面所有的同一个变量名都变成优先级最高的那个变量名,自然就打印200
但是原本的其他优先级低的变量本身值还是不会被改的,只是此时优先级低的变量名在代码块看似失效了
四、变量名优先级和名字遮蔽机制
因为除了运算符有优先级,变量之间也有优先级,变量之间的优先级针对是在代码块里面同一个变量名在不同作用域
变量的优先级看代码块就近原则,看代码块离哪个变量近,哪个变量在代码块里面,哪个优先级就高
局部变量在代码块里面,第一个val,局部变量优先级最高,打印200,但此时会触发一个机制,加做名字遮蔽机制
300、100 这两个变量内存里的值仍然保留不变,只是名字val被局部变量遮蔽,访问不到它们,不是把它们的值改成 200。
就记住发生名字遮蔽后,代码块里面所有的同一个变量名都变成优先级最高的那个变量名,自然就打印200
但是原本的其他优先级低的变量本身值还是不会被改的,只是此时优先级低的变量名在代码块看似失效了
变量名的优先级对比
局部变量大于全局变量等于匿名命名空间成员,但全局变量和匿名命名空间在一起会产生歧义性
虽然局部变量优先级大于全局,局部会发生名字遮蔽机制,在C语言语法里面无法获得全局值但是在C++可以
C++在代码块里面局部和全局重名的情况下打印全局变量
cpp
#include<iostream>
using namespace std;
int val=100;
int main()
{
int val=200;
cout<<"val的值是"<<val<<endl; 局部变量就是正常这样
cout<<"val的值是"<<::val<<endl; 当不是命名空间的变量名前面加域域运算符,就默认这个变量是全局变量
return 0;
}
C++中当不是命名空间的变量名前面加域运算符,就默认这个变量是全局变量