一、命名空间namespace
定义变量、函数时,定义的名称可能会和头文件中或者自己重复使用的名称冲突;namespace可以对标识符的名称进行本地化,以避免冲突的问题;
## 例如:
## 出现这种问题的原因:
(1)在头文件stdlib里面使用了rand,并且还是一个指针类型的,这与我们自己在全局定义的rand名称冲突;当然把rand定义在main函数里面不会冲突,这是因为就近原则,会先在局部寻找;
(2)若是在同一个作用域定义两个名称相同的变量,也会冲突;
使用namespace可以解决这种问题;
1、namespace定义
(1)namespace是一种关键字,后面跟上命名空间的名称,这个名称是我们自己命名的,然后接上{},{}里面是空间的成员,成员可以是变量、函数、或者自定义类型(如:结构体),{}后面不用像结构体那样接上分号 ' ; ' ;
(2) namespace本质上是一个域,这个域定义在全局域里面,这个域相当于一堵墙,把域里面的成员包起来,不同的域里面可以起相同名称的不同变量,成员名称如何起不受外面的影响,避免了冲突;
(3)namespace只能定义在全局,可以嵌套定义;
(4)有两个或者多个名称相同的命名空间namespace是允许的,此时它们会自动合并;
(5)命名空间里面的成员变量的生命周期不会因为命名空间的存在而改变,里面的成员变量的生命周期还是在程序完成时结束;不像局部变量,在那个所在的函数结束后生命周期就结束了;
(6)C++标准库都放在名称为 std 的namespace中。
2、代码演示:
1(::作用域限定符):
对比上面的代码,这段代码定义了一个命名空间space1,把我们自己想定义的rand定义在里面,这个rand就不会和头文件中的指针类型的rand冲突;
使用命名空间要用域作用限定符 :: ,这个符号前面加上域的名称表示在这个域之下进行使用;当前面不接名称时,就是默认在全局之下查找;
例如:
第一个打印的是3,它是就近原则查找局部;第二个是在全局;第三个在space1域里面;
2(嵌套定义、同名定义)
首先命名空间不能定义在局部,必须定义在全局域;
嵌套定义:
namespace space3
{
int a = 9;
struct S
{
char c;
};
namespace space4
{
int b = 0;
}
}
int main()
{
printf("%d\n", space3::a);
printf("%d\n", space3::space4::b);
struct space3::S s;
s.c = 'x';
printf("%c\n", s.c);
return 0;
}
嵌套定义使用时要从最外面的命名空间开找起;
在命名空间里面定义一个结构体变量,使用时在结构体名称前面加上 命名空间名称(space3)和域作用限定符( :: ),无论命名空间嵌套了几次,使用结构体时,把struct放在最前面;
同名定义命名空间:
在头文件中:
在源文件中:
运行结果:
二、命名空间的使用
使用到 using 展开一个命名空间,方便进行访问namespace里面的成员变量;
1、using使用的三种场景:
具体有三种展开方式:
(1)不展开:使用域作用限定符去指定访问命名空间里面的变量;这种方式在大型项目里面频繁使用,也最安全;
(2)使用using展开命名空间中某一个变量,后续使用这个变量时不需要再用 :: 域作用限定符;使用这种方式时需要保证这个成员变量名在程序中不会产生冲突;
(3)把命名空间全部展开,在平时代码量较少时使用这种方式,方便后续对命名空间内变量的访问;
2、代码演示:
using展开一般写在全局域,这里只是为了方便演示;
展开某一个成员时,在using后面接上命名空间的名称和 :: 以及那个成员的名称,以分号结尾;
直接展开整个命名空间:
在using后面接上namespace和命名空间名称,以分号结尾;
三、输入输出
<iostream>是Input Output Stream的缩写,是标准的输入、输出流库,定义了标准的输入输出对象;
<<是流插入运算符,>>是流提取运算符;
cout、cin、endl都放在一个叫std(standard)的命名空间里面,所以在使用的时候要展开这个命名空间;
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
int main()
{
int a = 0;
double b = 0.1;
char c = 'x';
cout << a << ' ' << b << ' ' << c << endl;
//虽然已经展开,但是这样写可以;在没有展开时,必须在前面加上std::
std::cout << a << ' ' << b << ' ' << c << std::endl;
//cout和cin可以自动识别类型
cin >> a;
cin >> b >> c;
cout << a << ' ' << b << ' ' << c << endl;
return 0;
}
关于<<和cout搭配、>>和cin搭配;
就拿<<和cout来说:<<是流插入运算符,那么就说明要插入数据进入流,既然是插入数据,那么说明数据已经定好值了,此时就是输出;同时<<也是指向cout的,说明要把数据传到流;
>>是流提取运算符,说明要从流里面提取一个数值,那么说明变量的数值没有定好值,>>指向的是变量,那么要在控制台输入一个数值,传给>>指向的变量,对应的就是输入;
四、缺省参数(默认参数)
1、缺省参数定义:
缺省参数是在函数声明或者定义时,给函数指定一个缺省值,若是没有指定实参,则使用缺省值,否则使用实参;缺省参数分为全缺省和半缺省参数(缺省参数也叫默认参数)
全缺省就是形参全部设置一个缺省值;半缺省就是部分给缺省值;设置缺省值的时候规定从右往左设置,不能间隔或者跳跃设置;
调用带缺省值的函数时,函数传参从最左边开始传实参,传实参也不能跳跃或者间隔传入;
若是函数声明和函数定义不在一起,使用缺省参数时,缺省参数不能同时出在在函数声明和函数定义中,规定给在函数声明中;
2、代码演示:
全缺省:
在传参时若是跳跃传参会报错:
半缺省:
没有默认参数的位置必须要传入实参;
设置缺省参数时不按照从右往左顺序:
五、函数重载
一、定义:
C++支持在同一作用域定义同名的函数,这就是函数重载;
但是要满足条件:
(1)函数名称相同;
(2)同名函数的形参个数或者类型不同;
这样C++出现了多态的行为,使用起来也更加灵活;C不支持函数重载;
另外:函数的返回类型不同不能作为判断两个函数是否重载的条件;必须依靠形参来判断。
二、代码演示:
1、类型不同
2、个数不同:
3、当缺省参数出现在函数重载的情况下时,传参不正确系统会报错:
此时不知道调用哪个函数,因为第二个函数定义的形参c是缺省参数,此时调用哪个都可以,此时为了避免错误只有在把实参写完整,之后编译器才会知道要调用第二个函数;
这种情况的两个函数同样还是函数重载。