目录
一、前言
上面我们已经写出了我们人生中第一个C++代码,现在让我们学习一下C++中新增加的功能缺省参数和函数重载以及引用吧。
二、正文
1.缺省参数
- 缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实参,则采用该形参的缺省值 ,否则使用指定的实参,缺省参数分为全缺省和半缺省参数。(有些地方缺省参数也叫默认参数)
- 全缺省就是全部形参给缺省值,半缺省就是部分形参给缺省值。C++规定半缺省参数必须从右往左依次连续缺省,不能间隔跳跃给缺省值。
- 带缺省参数的函数调用,C++规定必须从左往右依次给实参,不能跳跃给实参。
- 函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省值。
1.1缺省参数的使用
cpp#include<iostream> using namespace std; int ADD(int x=10, int y=20) { return x + y; } int main() { printf("%d\n", ADD());//这个会输出30,因为没有传实参,会默认缺省值就是形参,如这里的10,20; printf("%d\n", ADD(1, 2));//当给实参的时候,会将用户需要的实参传给实参,这里的是1,2; return 0; }
- 对于缺省,分为全缺省和半缺省:
cpp#include<iostream> using namespace std; int ADD(int x=10, int y=10,int z) { return x + y+z; } //半缺省 int main() { //注意:C++规定半缺省参数必须从右往左依次连续缺省,不能间隔跳跃给缺省值。 // 带缺省参数函数的调用,C++规定必须从左往右依次给实参,不能跳跃给实参。 // 1、这里就是违背了从左往右给实参的规定 // //printf("%d\n", ADD(1, ,3)); //2、这里就是违背了半省参数必须从右往左依次连续缺省,不能间隔跳跃给缺省值这一规定。 printf("%d\n", ADD(1, 2, 3)); //将ADD函数改为ADD(int x=10, int y=10,int z=30) //或ADD(int x, int y=10,int z=30)就可以正常运行。 return 0; }
cpp#include<iostream> using namespace std; int ADD(int x=10, int y=10,int z=30)//全缺省函数的形参依次缺省即可 { return x + y+z; } //全缺省 int main() { printf("%d\n", ADD(1, 2, 3)); return 0; }
2.对于缺省参数不能声明和定义同时给:
我们首先建立了两个文件,一个cpp文件和.h文件
2.函数重载
- C++支持在同一作用域中出现同名函数,但要求这些同名函数的形参不同 ,可以是参数不同或者类型不同。这样C++函数调用就表现了多态行为,使用更灵活。C语言是不支持同一作用域中出现同名函数的。
cpp#include<iostream> using namespace std; //1、参数数量不同 int ADD(int x=10, int y=20,int z=30) { return x + y+z; } int ADD(int x = 10, int y = 20,int z=30,int a=40) { return x + y+z+a; } //2、参数类型不同 int ADD(int x = 10, int y = 20) { return x + y ; } double ADD(double x = 10.11, double y = 20.11)//值得注意的是函数返回值不同不能作为函数重载条件 { return x + y; } //3、参数顺序不同 int ADD(int x = 10, char y = 20) { return x+y ; } int ADD(char y= 20, int x = 10) { return x+y; } int main() { printf("%d\n", ADD(1, 2, 3,4)); return 0; }
- 值得注意的是:值得注意的是函数返回值不同不能作为函数重载条件。
3.引用
3.1引用的概念和定义
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间(即它们指向同一处空间,地址相同)。比如:水浒传中李逵外号"黑旋风"、宋江外号"铁牛",林冲外号"豹子头"。
引用方法:类型&引用别名=引用对象。
例如:
- 值得注意的是:C++中为了避免引用太多的运算符,会复用C语言中的一些符号,比如C++中的输入<<,输出>>。这里引用也和取地址使用同一个符号&,大家注意使用方法角度区分就行了。
3.2引用的特性
- 引用在定义时必须初始化。
- 一个变量可以有多个引用。
- 引用一旦引用一个实体,再不能引用其他实体。
cpp#include<iostream> using namespace std; int main() { int a = 10; //1、下面这行代码没有给ra初始化,会报错 //int& ra; //2、下面这三行代码为我们讲述了一个变量可以有多个引用这一规则 //打个比方,张明在学校被同学起外号叫"鸡哥",在家被妈妈叫"小明" //所以说张明可以拥有无数个外号,因为这些外号指向的都是他本人。 /*int a = 10; int& ra = a; int& rb = a;*/ //3、下面四行代码中第四行因为触犯了---引用一旦引用一个实体,再也不能引用其他实体这一规则。 //这就好比张明很瘦小,同学们给他叫细狗。然后有人把这一外号套给一个很胖的人,很明显这是不合适的。 int a = 10; int b = 20; int& ra = a; int& ra = b;//报错 return 0; }
3.3引用的使用
- 引用在实践中主要用于引用传参和引用做返回值中减少拷贝提高效率和改变引用对象同时改变引用对象。
- 引用传参跟指针传参功能是类似的,引用传参相对更方便一些。
- 引用返回值的场景相对比较复杂,我们在这里简单讲了一下场景,还有一些内容后续类和对象章节中会继续深入讲解。
- 引用和指针在实践中相辅相成,功能有重叠性,但是各有特点,互相不可替代。C++的引用跟其他语言的引用(如Java)是有很大的区别的,除了用法,最大的点,C++引用定义后不能改变指向,Java的引用可以改变指向。
- 一些主要用C代码实现版本数据结构教材中,使用C++引用替代指针传参,目的是简化程序,避开复杂的指针,但是很多同学没学过引用,导致一头雾水。
- 上面就是我们用引用代替一级指针的引用,当然了指针也可以被引用,这样就相当于二级指针的作用,如:
cppint a=10; int*pa=&a; int*&ra=pa;//ra就是对一级指针pa的引用。
3.4const引用
- 可以引用-个cons对象,但是必须用Const31用。const3用地可以引用暂通对象,因为对象的访问权限在引用过程中可以缩小,但是不能放大。
- 不需要注意的是类似 int& rb = a*3; double d = 12.34: int& rd =d;这样一些场景下a*3的和结果保存在一个临时对象中,int& rd = d也是类似,在类型转换中会产生临时象存储中间值,也就是时,rb和rd引用的都是临时对象,而C+规定临时对象具有常性,所以这里就触发了权限放大,必须要用常引用才可以。
- 所谓临时对象就是编译器需要一个空间暂存表达式的求值结果时临时创建的一个未命名的对象,C++中把这个未命名对象叫做临时对象。
cpp#include<iostream> using namespace std; int main() { //下面属于权限放大,a被const限制住了(只能看不能改),而ra是a的引用,必须 //也使用const修辞才行,否则就是权限放大 /*const int a = 10; int& ra = a;*/ //这是正确写法const int&ra=a; //下面是对引用对象ra的权限缩小,初定义的时候a是可修改的 //ra被const修辞以后ra不能改了,只能看,但是a依旧可以修改 //因此对于引用对象来说权限只能小于或等于被引用的对象而不能大于 //就比如ra的权限只能小于或等于a,却不能大于a。 int a = 10; const int& ra = a; return 0; }
3.5指针和引用的关系
- C++中指针和引用就像两个性格迥异的亲兄弟,指针是哥哥,引用是弟弟,在实践中他们相辅相成,功能有重叠性,但是各有自己的特点,互相不可替代。
- 语法概念上引用是一个变量的取别名不开空间,指针是存储一个变量地址,要开空间。引用在定义时必须初始化,指针建议初始化,但是语法上不是必须的。
- 引用在初始化时引用一个对象后,就不能再引用其他对象;而指针可以在不断地改变指向对象。引用可以直接访问指向对象,指针需要解引用才是访问指向对象。
- sizeof中含义不同,引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节,64位下是8byte)
- 指针很容易出现空指针和野指针的问题,引用很少出现,引用使用起来相对更安全一些。
4.inline
- 用inline修饰的函数叫做内联函数,编译时C++编译器会在调用的地方展开内联函数,这样调用内联函数就需要建立栈帧了,就可以提高效率。
- inline对于编译器而言只是一个建议,也就是说,你加了inline编译器也可以选择在调用的地方不展开,不同编译器关于inline什么情况展开各不相同,因为C++标准没有规定这个。inline适用于频繁调用的短小函数,对于递归函数,代码相对多一些的函数,加上inline也会被编译器忽略。
- C语言实现宏函数也会在预处理时替换展开,但是宏系数实现很复杂很容易出错,目不方便调试,C++设计了inline目的就是替代C的宏函数。
- VS编译器debug版本下面默认是不展开inline的, 这样方便调试,debue教水相展开需要设置一下。
- lnline不建议声明和定义分离到两个文件,分离会导致链接错误。因为inline被展开,就没有函数地址链接时会出现报错。
关于inline这部分讲起来有些复杂,小伙伴有兴趣的可以自己手动查一下相关资料。
5.nullptr
NULL实际上是一个宏,在传统的C头文件(stddef.h)中,可以看到如下代码:
cpp#define NULL #ifdef__cplusplus #define 0 #else #define NULL ((void*)0) #endif #endif
- C++中NULL可能被定义为字面常量0,或者C中被定义为无类型指针(void*)的常量。不论采取何种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,本想通过f(NULL)调用指针版本的fint)函数,但是由于NUL被定义成0,调用了f(intx),因此与程序的初衷相悖。f(void*)NULL)调用会报错。
- C++11中引入nullptr, nullptr是一个特殊的关键字,nullptr是一种特殊类型的字面量,它可以转物成任意其他类型的指针类型。使用nullptr定义空指针可以避免类型转换的问题,因为nullptr只能隐式地转换为指针类型,而不能被转换为整数类型。
从以上结果可知在C++中NULL++可能++被定义成整形0;因此在后面我们编写程序表示空指针时最好使用nullptr,可以避免一些不必要的错误。
三.结言
今天的知识分享就到这里了,如果有讲不到位或者有误的地方,欢迎大佬们的指正,我们下期再见,拜拜~