一起think C++:C++基础篇(一)—— namespace、IO、缺省参数与函数重载 文章目录1.namespace1.1为什么要有namespace1.2怎么使用namespace1.2.1using1.3namespace在使用中的注意事项2.C的输入输出2.1为什么要有cin和cout2.1.1从面向过程到面向对象2.2cin和cout的使用2.2.1竞赛中节省时间的代码3.缺省参数3.1为什么要有缺省参数3.2缺省参数的使用时的注意点4.函数重载4.1为什么要有函数重载4.2函数重载注意点4.2.1返回值不同不构成函数重载4.2.2构成函数重载产生歧义的情况5.总结这里是think的博客希望可以一起交流知识一起think今天我们来学习C一起来think首先学习C需要有C语言的基础知识想学习C语言可以到我的其他博客看看。1.namespace#includeiostreamusingnamespacestd;intmain(){inta10;cout10endl;return0;}第一个重要的点就是namespacenamespace是命名空间域其中using的意思是展开所以using namespace std;的意思是展开std这个命名空间域。1.1为什么要有namespace情况1stdlib.h头文件中有rand函数 此时rand既是全局变量又是函数名都在全局域中命名冲突了此时编译器不知道要使用那一个进而报错。情况2当多人协作的时候可能也会命名冲突这个是最常见的不像情况1那样是改一改变量名就行了毕竟要协作的项目可能一个变量名写了很多次那么是你改还是他改呢都没有义务改。其中额外提一点如果rand从全局变量(属于全局域)变成了局部变量属于局部域就不是命名冲突了那么在main函数中使用rand使用的是局部域里的这个其实就是有局部有全局使用的是局部的知识点了。1.2怎么使用namespace也正是有这些实际的问题C中就新增了一个namespace关键词即命名空间域。#includestdio.h#includestdlib.hnamespacecpp{intrand10;}intmain(){printf(%p,rand);return0;}这里用到的就是rand函数而不是rand变量了因为我们加上了cpp这个命名空间域编译器默认是不会去命名空间中找的。那么怎么使用cpp中的rand变量呢使用域作用限定符::#includestdio.h#includestdlib.hnamespacecpp{intrand10;}intmain(){printf(%d,cpp::rand);return0;}C语言中还有一个问题也可以用域作用限定符解决一个全局变量和一个局部变量默认使用局部前面只加上::就可以使用全局的了。#includestdio.hintrand100;intmain(){intrand10;printf(%d,rand);printf(%d,::rand);return0;}namespace中不仅可以定义变量还可以定义类型和函数。namespace可以嵌套定义#includestdio.hnamespacecpp{namespacec{intrand100;}}intmain(){printf(%d,cpp::c::rand);return0;}1.2.1usingusing namespace cpp是展开cpp命名空间和头文件的展开对比来看头文件的展开是将头文件中的内容拷贝到原处而命名空间的展开表示的是让编译器查找名称出处的时候会去该展开的命名空间中查找。问题如果展开了两个命名空间但是内部有名称相同的变量就会命名冲突所以using一般使用在我们日常写代码的时候在项目中也可以使用但是一般是这样使用using cpp::rand表示展开cpp中的rand即使用rand时查找出处的时候会去cpp中找而大的项目中一般不会直接把命名空间的全部内容都展开一般是靠这个展开常用又不容易冲突的。1.3namespace在使用中的注意事项我们写程序的时候经常会头源文件分离会在头源文件中写两遍命名空间在头文件展开的时候命名空间不会冲突而是会合并当然不是物理上的拼在一起而是逻辑上的合并。C中有4个域函数局部域全局域命名空间域和类域其中局部域和全局域生命周期就是局部和全局但命名空间域和类域只会改变作用域不会改变生命周期其中命名空间不可以定义在局部所以可以说命名空间的生命周期是全局的但是类域可以定义在全局也可以定义在局部。2.C的输入输出区别于C语言的printf和scanf函数C中输入输出靠的是istream和ostream类的对象cin和cout2.1为什么要有cin和cout原本有了printf和scanf了已经可以进行输入输出了那么为什么C中还要引入cin和cout呢2.1.1从面向过程到面向对象cin和cout实际上是为了实现C面向对象的特性而诞生的因为我们在使用printf和scanf函数的时候其实是需要我们告诉函数我要用什么格式打印数据我要用什么格式读取数据这里是面向过程但是我们要的是面向对象所以我们设计出cin和cout而cin和cout是自己识别格式。其中cin和cout还可以支持自定义类型的输入输出现在的知识只能提到这两个点以后的点以后再讲。2.2cin和cout的使用cin和cout在std域内也在iostream头文件内。#includeiostream#includestdio.husingnamespacestd;intmain(){inta10;floatb10.3;intc0;cinc;coutaendlbendlcendl;return0;}其中endl是一个函数现在可以认为endl的作用是换行加刷新缓冲区。C中的换行不刷新缓冲区和是流插入和流提取操作符其中它们也是左移右移操作符。iostream可能会间接包了stdio.h当然不是所有编译器都会只有这是编译器的未规定行为。2.2.1竞赛中节省时间的代码#includeiostreamusingnamespacestd;intmain(){// 在io需求⽐较⾼的地⽅如部分⼤量输⼊的竞赛题中加上以下3⾏代码// 可以提⾼CIO效率ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);return0;}第一句表示解除 C 标准输入输出流cin/cout与 C 标准输入输出流scanf/printf之间的同步使 C IO 使用独立的缓冲区从而提高输入输出效率。第二句表示解除 cin 和 cout 之间的绑定关系。默认情况下cin 在进行输入前会自动刷新 cout 的输出缓冲区解除绑定后cin 不再自动刷新 cout可以减少额外开销提高效率。敢这样也是因为竞赛中出现大都是大量输入之后比如求和一百万次再输出一次最后的结果所以解除绑定以后可以减少cin输入前都要检查cout的输出缓冲区的时间解除 cout 与其他输出流之间的绑定关系。(一般没用因为cout默认没有绑定其他输出流)没有解除。有解除。3.缺省参数缺省参数其实就是让参数有默认值如果传值的话就用传递的值没有的话就用缺省的。#includeiostream#includestdio.husingnamespacestd;intAdd(inta,intb1){returnab;}intmain(){intcAdd(1,3);coutcendl;cAdd(1);coutcendl;return0;}3.1为什么要有缺省参数为了减少多余的参数因为可能一个参数写了很多遍都还是一个固定的值那么缺省的作用就有了直接将这个参数变为缺省参数即可减少多余代码。一般语言在更新的时候都会兼容前面的版本就是因为可能很多项目用了之前版本的语法这样更新可以保证旧代码在新编译器下也可以运行这里也是一样如果我们要改变一个函数的参数从3个变为4个但是已经有很多的接口都是3个的这里采用缺省参数就可以避免报错。日期类等类一般也需要缺省参数来保证不传参的时候也会默认值。3.2缺省参数的使用时的注意点缺省参数只能从右到左填并且不可以跳跃填而调用的时候实参只能从左到右填这个语法也是可以改的但是要引入占位符但是C连C语言中的printf和scanf占位符都没有引入到cout和cin上也可以见得缺省参数中也没有占位符所以在没有占位符的情况下如果不遵守这个规则就会产生歧义。错误代码#includeiostream#includestdio.husingnamespacestd;intAdd(inta1,intb){returnab;}intmain(){intcAdd(1,3);coutcendl;cAdd(1);coutcendl;return0;}在没有占位符情况下编译器无法判断这个1是传给a的还是b的C官方不支持这种语法c Add(,1);要是有占位符这种写法是可以实现的值得注意的是可能有人认为在处理缺省参数的时候是在运行中处理的认为是在执行到调用函数那里去到函数内部发现有缺省参数于是就给对应的参数赋缺省值。实际上是在编译期间处理完了比如Add(1);在编译阶段直接当成Add(1,1);来处理。缺省参数分为全缺省全部参数都缺省和半缺省参数一部分参数缺省要从右到左不能跳跃。函数声明和定义分离时不能同时在声明和定义给缺省值规定必须在函数声明中给。因为如果函数声明和定义分离那么编译器是根据声明来处理缺省参数因为是分离编译所以要在声明中给缺省参数而在定义中给缺省参数是未定义行为可能可以通过比如VS2022可以通过以声明为主定义中的直接忽略也可能会报错如果定义和声明的缺省参数一致那么就是重复定义不一致就是定义冲突。4.函数重载在同一作用域内函数名可以相同。#includeiostream#includestdio.husingnamespacestd;intAdd(inta,intb){returnab;}floatAdd(floata,floatb){returnab;}intmain(){intcAdd(1,3);coutcendl;floatdAdd(1.1f,2.2f);coutdendl;return0;}4.1为什么要有函数重载C语言中如果我们要写int和float类型的加函数的话函数名应该为Addi和Addf调用的时候也是比较麻烦现在就可以直接定为Add了调用的时候写的都是Add。函数重载就是为了帮助记忆和让代码更加的清晰。函数重载也初步体现了把事情交给编译器做的特性。4.2函数重载注意点4.2.1返回值不同不构成函数重载函数重载成立的条件是同一作用域内同名函数参数个数或者类型不同。其中函数返回值不同不算因为如果参数个数和类型相同但是返回值不同也是重载的话会产生歧义因为在函数调用的时候使用的是函数名和函数参数没有用到返回值的所以编译器将会不知道调用哪一个函数。错误代码#includeiostream#includestdio.husingnamespacestd;intAdd(inta,intb){returnab;}floatAdd(inta,intb){returnab;}intmain(){intcAdd(1,3);coutcendl;return0;}这里就有歧义了编译器不知道调用哪一个。4.2.2构成函数重载产生歧义的情况有着全缺省参数的函数和无参的函数是构成函数重载的满足函数参数的个数或者类型不同的条件至于是否有缺省参数和是否构成函数重载无关。#includeiostream#includestdio.husingnamespacestd;intfun(){return1;}intfun(inta10){returna;}intmain(){intcfun();coutcendl;return0;}这里有歧义编译器不知道调用哪一个函数如果换成fun(1);就可以了就调用的是第二个fun。那么这种情况下如果还想要保持函数重载的话这里的歧义没有办法解决不要这样调用即可但是如果不要保持函数重载了可以给其中一个加上namespace命名空间即可。5.总结谢谢观看