C++初阶--基本语法讲解
文章目录
- C++初阶--基本语法讲解
- 缺省参数
- 上篇博客补充:
- 引用
- 引用的概念和定义
- 引用的特性
- 引用的使用
- const的引用
- 指针和引用的关系
- 结语
大家好,很高兴和大家见面,给生活加点impetus!!开启今天的编程之路!!
今天我们进一步学习C++的基本语法,为C++之旅打下坚实基础。
作者:٩( ‘ω’ )و260
我的专栏:C++初阶,数据结构初阶,题海探骊,c语言
感谢点赞,关注!!
C++初阶–基本语法讲解
缺省参数
我们逐个来说明缺省参数的特性:
缺省参数是声明或定义函数时为函数的参数指定⼀个缺省值。在调⽤该函数时,如果没有指定实参则采⽤该形参的缺省值,否则使⽤指定的实参,缺省参数分为全缺省和半缺省参数
全缺省:
半缺省:
半缺省参数至少需要传递未赋值的形参的个数的实参个数
理解:缺省参数实参没传,就用形参的数值,实参传递了,就用实参的数值
那我们可不可以传实参的时候,传给指定的缺省参数呢?
例如:
这样是不被允许的!!
那我们改变实参不行,可不可以改变缺省参数呢?
例如:
虽然我们半缺省参数的实参位置一定传递了实参,但是代码仍然出错
原因主要是顺序问题:
我们这里直接来总结一下结论:
1:全缺省就是全部形参给缺省值,半缺省就是部分形参给缺省值。C++规定半缺省参数必须从右往左依次连续缺省,不能间隔跳跃给缺省值
2:函数实参只能从左往右给,不能跳跃着给或者间隔着给
3:函数声明和定义分离时,缺省参数不能在函数声明和定义中同时出现,规定必须函数声明给缺省值,如果定义和声明分离,在点h文件中说明缺省值的大小,点c文件中不用说明大小
上篇博客补充:
我们上篇文章学习了函数重载以及缺省参数,我们先来看一段代码再来讲解一个细节:
当我调用fun函数时,第一次有实参,这样我就能判断一定是调用下方具有缺省参数的函数,第二低调用没有传递实参,所以编译器不能判断具体是调用的哪一个函数,这种形式的传递实参,两种函数形参形式都满足实参条件。
注意:根据函数重载的定义,这种形式是满足函数重载的
引用
引用的概念和定义
引⽤不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间
注意:概念上是不会为引用变量开辟空间的
公式:数据类型& 引用变量=引用对象
来举例一下:
我们可以发现两者地址相同,这也验证了定义中所说的!!
同理:我们也可以给别名取别名,仍然代表同一个引用对象
例如:
#include<iostream>
using namespace str;
int main()
{
int a=0;
int& ra=a;
int& rra=ra;
}
这样也是不会报错的!!
引用的特性
十分重要!!
1:引用在定义的时候必须初始化
2:一个变量可以有多个引用
3:引用一旦引用了对象,不能再改变引用对象
第二点我们在上面的代码中就已经明白了,我们再来用代码来验证1,3点:
引用的使用
我们先来说明结论:
1:体现在引用传参和引用做返回值,目的:减少拷贝,提高效率,改变引用对象的同时改变了被引用对象
我们来举例:
引用传参上:
这里我们直接传值调用,接收形参的实参改为引用形式。
引用做返回值:
这里需要有一些细节来注意,下方是一个栈的结构,我们只讲解测试部分的代码。
首先我们需要明白传值返回的原理是什么?
返回值的时候,编译器会创建一个叫临时对象的空间,这个空间会存储返回值,返回的是临时对象,临时对象是具有常性的,他是一个右值,无法被修改,所以编译器会报错!!
引用返回的时候,返回的是别名,别名对象的地址是不变的,具有变性,是一个左值。所以编译器不会报错!!
这里需要总结左值和右值
1:左值和右值概念复杂,两者都为表达式。只需记忆:可以取地址的就是左值,反之为右值
2:左值和右值常见的类别:
右值:字面量(如’x’,数字30),临时对象,常量。
产生临时变量的操作:函数传值返回,表达式运算(如a+b),强制类型转换(如double转double型),函数对象作为参数等。
左值:变量声明与定义,解引用操作,数组元素访问,成员访问操作,函数返回左值引用,赋值表达式,自增自减等
这里我们重点来看右值的操作:
最后,其他右值的操作大差不差,基本相同。
返回的别名是可以直接修改的,本质是修改地址中的元素,取的别名,所以不会像传值调用具有值的拷贝,效率提高了
2:引用传参与指针功能类似,但是引用传参更加方便,两者相辅相成,以后书写代码的时候能够使用引用的地方就使用引用,实在不能使用的话就使用指针。
例如:链表类型必须使用指针,因为进行删除等操作时我们需要改变结点的指向,但是引用是不能改变指向的。
这里我们来复习一个点:
typedef struct LTNode{
....
....
}LTNode,*pLINode;
//后面代表我们把这个结点的地址typedef重命名,前面代表把结点重命名
我们在这里可以再来看一个代码,加深上面代码的理解:
int& func(int x,int y)
{
int ret=x+y;
return ret;
}
int main()
{
func(2,1)+=10;
}
请问这句代码有错没有,我们来看一下结果:
上面的代码肯定是有错误的,原因是访问野引用。
来看图解:
为什么那个int& STTop()函数却可以呢?
STTop函数执行结束,函数栈帧销毁,返回对象不在STTop的函数栈帧中,可以返回他的引用。
func函数执行结束,函数栈帧销毁,返回对象在func的函数栈帧中,不可以返回他的引用。
注意:空间的销毁是指空间已经还给操作系统了,我们的使用权限已经没
有了
这里我们还可以补充一个点:
因为栈使用数组实现的,我们有时候会发现,数组越界访问时有时候会报错,有时候不会报错,我们来说明一下数组越界访问的报错原理:
编译器会在数组末尾的开始放置标记位,如果标记位被修改,才会报错,如果越界访问很后面的元素,编译器大概率不会报错!!
最后,如果需要修改返回对象,就引用返回
const的引用
我们先来说明结论:
1:可以引用⼀个const对象,但是必须用const引用。const引⽤也可以引用普通对象,因为对象的访问权限在引用过程中可以缩小,但是不能放大。
注意该点:权限的放大和缩小只会涉及指针和引用
我们来用代码解释:
上述发生问题的地方只需要在最前方添加const即可,本质是权限放大,引用对象数值不能改,难道取别名之后就能够改了吗?这是不可能的
但是权限缩小语法正确。
指针和引用的关系
两者相辅相成,在C++中缺一不可。
这里我们主要来说明一下两者的区别:
1:引用概念上不会创建空间,指针需要创建空间,但是本质上引用也是需要空间消耗的,也是需要创建空间的的。来看反汇编,两者一模一样
2:引用定义时必须初始化,指针定义时不必强制初始化,最好还是要初始化
3:引用在初始化时引用一个对象后,就不能再引用其他对象;指针可以在不断地改变指向对象。
4:引用可以直接访问对象,指针需要解引用才能访问对象
5:sizeof:引用时为引用对象的大小,指针只有4字节(32位)或者8字节(64位)
6:指针容易出现野指针,空指针问题,引用相对比较安全。
7:以后能用引用就用引用,实在不行才会用指针。
结语
感谢大家阅读我的博客,不足之处欢迎指出,希望阅读此文,你能收获良多,编程能力稳固上升!!
书山有路勤为径,学海无涯苦作舟!!加油!!