1.命名空间
1.1命名空间的定义
为解决c中命名冲突问题C++中引入:命名空间(关键字:namespace)后面跟命名空间的名字,{}中即为命名空间的成员。命名空间中可以定义变量/函数/类型等。
namespace本质是定义出一个域,这个域跟全局域各自独立,不同的域可以定义同名变量,不同的域(可以理解成空间)。
C++中域分为函数
- 局部域:局部变量(函数中的变量)名字存放的地方
- 全局域:可理解成全局变量名字存放的空间
- 命名空间域:不同于局部域和全局域的独立命名空间
- 类域;
域影响的是编译时语法查找一个变量/函数类型出处(声明或定义)的逻辑,所有有了域隔离,名字冲突就解决了。
C++标准库都放在一个叫Std(standard)的命名空间中。
1.2命名空间的使用
1.2.1指定访问
第一种使用命名空间的方法,通过::来指定访问,如下:意思就是去newspace中查找a变量
//标准输入流、输出流库
#include<iostream>
//命名空间
namespace newspace
{
int a=1;//命名空间域a
}
int a=2;//全局域a
int main()
{
int a=3;//局部域a
printf("%d \n",a);
printf("%d \n",::a);//::前面是空白为指定访问全局域
printf("%d \n",newspace::a);//指定访问newspace里的a
}
1.2.2展开命名空间
用using ,如:using namespace std,不过实际项目开发中不建议usingnamespace std。
例子如下使用 using namespace
指令并不会将命名空间中的变量放到全局域中,而是允许代码中直接使用该命名空间内的变量和函数,而不需要每次都加上命名空间的前缀。在例子中,这样做的效果是让你能够直接使用 newspace
命名空间中的变量 a
,就像它是在全局作用域中一样,但实际上它还是属于 newspace
命名空间。
//标准输入流、输出流库
#include<iostream>
//命名空间
namespace newspace
{
int a = 1;
}
using namespace newspace;
int main()
{
int a = 3;
printf("%d \n", a);
printf("%d \n",::a);//::前面是空白为指定访问全局域
printf("%d \n", newspace::a);//指定访问newspace里的a
}
展开std的操作为:
//标准输入流、输出流库
#include<iostream>
//命名空间
namespace newspace
{
int a = 1;
int b = 31;
int c = 21;
}
// 直接展开会有风险,我们定义如果跟库重名,就报错了
//std 为库给的命名空间里面有常用的变量 本质和展开自定义命名空间一样
using namespace std;
using namespace newspace;
int main()
{
int a = 3;
printf("%d \n", a);
printf("%d \n",::a);//::前面是空白为指定访问全局域
printf("%d \n", newspace::a);//指定访问newspace里的a
}
1.2.3展开命名空间的部分变量(推荐)
用法指令如下:编译结果可以看到不展开就用b是会报错的,
//标准输入流、输出流库
#include<iostream>
//命名空间
namespace newspace
{
int a = 1;
int b = 31;
int c = 21;
}
// 只展开命名空间的a变量(推荐)
using newspace::a;
int main()
{
printf("%d \n",a);
printf("%d \n", b);
}
把打印b注释掉
2.C++输入&输出
<iostream>是 Input Output Stream 的缩写,是标准的输入、输出流库,定义了标准的输入、输出对象。
std::cin 是 istream 类的对象,它主要面向窄字符(narrow characters(oftype char))的标准输入流。
std::cout 是 ostream 类的对象,它主要面向窄字符的标准输出流。
std:.endl 是一个函数,流插入输出时,相当于插入一个换行字符加刷新缓冲区。
<<是流插入运算符 ,
>>是流提取运算符。(C语言用这两个运算符做位运算左移/右移,cpp中依然能用)
使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动指定格式,C++的输入输出可自动识别变量类型(本质是通过函数重载实现的,这个以后会讲到),其实最重要的是C++的流能更好的支持自定义类型对象的输入输出。
3.缺省参数
缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参则采用该形参的缺省值,否则使用指定的实参,缺省参数分为全缺省和半缺省参数。(有些地方把缺省参数也叫默认参数)
全缺省:全部形参给缺省值,
半缺省:部分形参给缺省值。
函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省值。
#include<iostream>
//全缺省 即全都给默认值 这里的10,20,30 就是缺省值
void Func1(int a = 10, int b = 20, int c = 30)
{
std::cout << "a = " << a << std::endl;
std::cout << "b = " << b << std::endl;
std::cout << "c = " << c << std::endl << std::endl;
}
//全缺省 只有部分参数都给默认值(只能从右向左的参数给缺省值)
void Func2(int x , int y , int z = 60)
{
std::cout << "x = " << x << std::endl;
std::cout << "y = " << y << std::endl;
std::cout << "z = " << z << std::endl << std::endl;
}
int main()
{
/* 全缺省 */
Func1(); //a=10 b=20 c=30
Func1(1); //a=1 b=20 c=30
Func1(1,2); //a=1 b=2 c=30
Func1(1,2,3); //a=1 b=20 c=3
/* 半缺省(和全缺省用法一样) */
Func2(5, 6);//x=5 y=6 z=60
return 0;
}
4.函数重载
C++支持在同一作用域中出现同名函数,但是要求这些同名函数的形参不同,可以是参数个数不同或者类型不同。这样C++函数调用就表现出了多态行为,使用更灵活。C语言是不支持同一作用域中出现同名函数的。
ps:暂时的理解:在同一域中,定义两个同名的函数,但是形参的数据类型不一样这样也是合法的
如下:
#include<iostream>
void Func(int a = 10, int b = 20)
{
std::cout << "a = " << a << std::endl;
std::cout << "b = " << b << std::endl << std::endl;
}
void Func(int x, double y )
{
std::cout << "x = " << x << std::endl;
std::cout << "y = " << y << std::endl << std::endl;
}
int main()
{
Func();//因为全缺省 没传参
Func(1,1.3); //1.3是浮点型,所以会调用void Func(int x, double y )
return 0;
}
5.引用
引用不是新定义一个变量,而是给已存在变量取了一个别名(其实可以理解成取外号),编译器不会为引用变量开辟内存空间它和它引用的变量共用同一块内存空间。 用法在数据类型后面加&符号如定义:
int main()
{
int a = 10;
int& b = a; //b定义为a的别名,b本质还是a 只不过名字不一样
int& c = b; //c又是b的别名,所以c的本质也是a
int& d = a; //(可以想想给一个人取多少个外号,其实还是指的一个人)
b++; //还是作用在a上 a=11
c++; //c的本质其实也是a ,a=12
return 0;
}
引用的特点:
(一)引用指向是不能改变的
(二)引用改变实体也改变
(三)一个变量可以有多个引用
(四)引用不开辟新空间
int main()
{
int a = 0;
int& b = a;//b定义为a的别名,b本质还是a
int& c = b;//c又是b的别名,
int& d = a;
/*引用指向不能改变*/
int x = 11;
d = x; //是x赋值给d,也就是d=11
return 0;
}
常用场景:
1)做参数
void Swap(int& a, int& b) //x取别名a y取别名b
{
int tmp = a;//根据引用特性别名的改变会改变实体
a = b;
b = tmp;
}
int main()
{
int x = 0, y = 1;
Swap(x, y); //x,y传参
cout << x << " " << y << endl;//打印结果: 1 0
return 0;
}
2)做返回值
int& count(int a)
{
static int n = a;
n++;
return n;
}
int main()
{
int& ret = count(10);//ret是n的别命
cout << " ret= " << ret << endl; // 输出 n 的当前值
ret++; // 修改 ret 同时会修改 n
cout << " ret after increment= " << ret << endl; // 输出修改后的值
cout << " n after increment= " << count(10) << endl; // 确认 n 的值被修改
return 0;
}
/// 情况二 ///
//返回值设置为int型
int count(int a)
{
static int n = a;
n++;
return n;
}
int main()
{
int& ret = count(10); // 编译错误:不能用引用来接收一个普通的值
return 0;
}