C++关键字&&命名空间
近段时间学习了C++的相关内容, C++还是很火的编程语言!下面分享我的学习心得:关于C++关键字和命名空间的认识
1.C++关键字
C++总计63个关键字,C语言32个关键字
| asm | do | if | return | try | continue |
|---|---|---|---|---|---|
| auto | double | inline | short | typedef | for |
| bool | dynamic_cast | int | signed | typeid | public |
| break | else | long | sizeof | typename | throw |
| case | enum | mutable | static | union | wchar_t |
| catch | explicit | namespace | static_cast | unsigned | default |
| char | export | new | struct | using | friend |
| class | extern | operator | switch | virtual | register |
| const | false | private | template | void | true |
| const_cast | float | protected | this | volatile | while |
| delete | goto | reinterpret_cast |
2.命名空间
为什么存在
主要是为了为了解决命名冲突
例子:
#include<stdio.h>
#include<stdlib.h>//里面包含rand函数
int rand = 0;//全局变量rand
int main()
{
printf("rand = %d\n", rand);//编译器不知道打印的是函数的地址(函数名 == 函数的地址)还是全局变量rand的值
printf("%d\n",rand());//这样没问题,这样相当于是调用rand函数
return 0;
} 若rand为全局变量则有问题了,因为rand函数和rand变量都是全局变量,编译器不知道哪个是你要打印的是哪个

但是写成这样没问题:
#include<stdio.h>
#include<stdlib.h>
int main()
{
int rand = 0;//此时的rand变量为局部变量,局部优先,
printf("rand = %d\n", rand);//0 局部优先,打印的是局部变量rand的值
return 0;
}0 此时rand为局部变量就没有问题,全局变量和局部变量可以同名,使用时原则为:局部优先(先使用局部变量)
编译器寻找变量的规则是:先在该作用域中寻找该局部变量,找不到再去全局变量中找,如果还是找不到,就会报错
在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突,使用命名空间的目的是对标识符的名称进行本地化,以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的,
- 使用命名空间后
#include<stdio.h>
#include<stdlib.h>
namespace M_Space//定义一个叫M_Space的命名空间-域
{
int rand = 0;
}
int a = 10;
int main()
{
printf("rand = %d\n", rand);
// :: 域作用限定符
printf("命名空间的rand = %d\n", M_Space::rand);//表示rand再M_Space这个域中寻找
M_Space::rand = 10;
printf("修改值后:命名空间的rand = %d\n", M_Space::rand);
printf("%d\n" , ::a);//10
//若域作用限定符的坐标是空白,则说明再全局域中寻找
return 0;
} 
命名空间的定义
命名空间是全局的,命名空间里面的成员也是全局的变量
定义命名空间需要使用到
namespace关键字,后面跟命名空间的名字,然后接一对{},{}中即为命名空间的成员
- 例子
namespace MS //MS是命名空间的名字 - 域
{
int a = 0;//a是全局变量,放在静态区,是MS命名空间的成员,
} 域中的成员变量是不能在域中赋值的!只能初始化时候赋初始值
命名空间中的内容,既可以定义变量,也可以定义函数,也可以创建类型(结构体,联合体..)
namespace M_Space
{
int a = 0;
int Add(int x, int y)
{
return x +y ;
}
struct Student
{
int age;
char sex[7];
};
} - 命名空间中的结构体使用时的注意事项
namespace M_Space
{
struct Student
{
int age;
char sex[7];
};
}
M_Space::struct Student stu;//err
struct M_Space::Student stu;//写法1
M_Space::Student stu;//写法2 - 命名空间内部的变量可以定义时初始化,但是不可以在命名空间内再次赋值,要再次赋值要在其它函数内赋值
namespace M_Space
{
int a = 0;//定义时初始化
int b;//只定义不初始化
a = 10;//err
b = 5;//err
}
M_Space::a = 10;//err 在外部赋值也不可以,要在函数内部赋值
void test()
{
M_Space :: a = 10;//可以
} 
原因分析:
命名空间内创建的是全局变量,全局变量要在函数内部赋值,初始化时只能赋初始值
int a = 10;
a = 20;//err
int main()
{
a = 10;//OK
return 0;
} 2.命名空间可以嵌套
namespace N1
{
int a = 2;
namespace N2
{
int b = 3;
}
}
int main()
{
N1::a = 2;
N1::N2::b = 1;
//同样也是使用::域作用限定符进行逐层访问
printf("a = %d b = %d\n", N1::a, N1::N2::b);// 2 1
return 0;
} 3.同一个工程中允许存在多个相同名称的命名空间,编译器最后会合成同一个命名空间中,
namespace N1
{
int a = 0;
int b = 2;
}
namespace N1
{
int a = 1;
}
int main()
{
printf("a = %d b = %d\n", N1::a, N1::b);
return 0;
} 
相同名称的命名空间,最后会合成同一个命名空间中,所以相同名称的命名空间里面的成员名字不能相同,否则会报错
命名空间不影响变量的属性,它还是全局变量,只是影响了编译器找该变量的规则 命名空间里面可以只放声明(函数声明)
命名空间的使用
方法1:加命名空间名称及作用域限定符 ::
命名空间名称 :: 成员名;
namespace M1
{
int a = 10;
}
int main()
{
printf("before:M1::a = %d\n", M1::a);//10
M1::a = 20;
printf("after:M1::a = %d\n", M1::a);//20
return 0;
} 优缺点:
- 优点:不会造成命名污染 缺点:使用麻烦
方法2:使用using将命名空间中成员引入
using 命名空间名称 :: 要展开的成员;
namespace M1
{
int a = 10;
int b = 20;
}
//单独展开M1中的a变量,其它不展开
using M1::a;
int main()
{
printf("a = %d\n", a);//10
printf("b = %d\n", b);//b未被引入,编译器找不到,会报错
return 0;
} 想要程序没问题:把b也展开
using M1::a; using M1::b;
方法3:使用using namespace命名空间名称引入
using namespace 命名空间名称 ;
这种写法是直接把整个命名空间展开,使用方便,但是命名空间的隔离作用就失效了
namespace M1
{
int a = 10;
int b = 20;
}
//把M1这个命名空间展开-展开到全局
using namespace M1;
int main()
{
printf("a = %d\n", a);//10
printf("b = %d\n", b);//20
return 0;
} namespace N1
{
int a = 2;
namespace N2
{
int a = 3;
}
}
using namespace N1;
int a = 0;
int main()
{
//printf("a = %d ", a);//err,未知要打印的是N1的成员变量a还是外部的全局变量a
printf("a = %d ", N1::a);//这样使用了域限定符就可以
return 0;
} 
命名空间N1展开之后,N1里面的全局变量a和外部的全局变量a重名了,N1失去了隔离作用
优缺点:
- 优点: 使用成员方便
- 缺点:由于是展开到全局,如果全局也有相同名字变量或函数名等,会造成命名污染,编译器报错

