文章目录
引用
引用的语法表层就是给变量起别名
1.发明原因
引用是为了完善指针的一些缺点而创造出来的,在一些场景下可以替代指针,但和指针有很大区别.详细见3.
2.语法
3.引用在C语言的应用
一
在递归中,若传参是没到一层栈帧都需要改变的,那就需要能不受创立新栈帧的变量,指针就是其一
递归创建二叉树时,要创建多少节点需要int*pi记录,因为在栈帧中,*pi的改变是不可以逆转的,不受跳出递归影响
同样作为引用传入,只要递归中改变,作用域外的值也会改变,不受跳出递归影响
二
在数据结构中,我们在改变链表的头结点时需要使用二级指针,这使的很多人都头疼,套来套去的令人混乱。———函数传参要改变指针的指向,就需要使用指针的指针。 如图这难免有些饶
而一些数据结构的书中,在头插部分如图第三和第二定义
第一和第三其实都是用二级指针解决,而第二是传入了头结点的引用,那么更改其引用,也就是改变其本身。这就避免了使用二级指针的麻烦
4.引用作为返回值的使用
首先我们要知道函数返回值的过程
从Count栈帧返回的值并不会直接赋给ret,而是通过创建临时变量来传递
后者也一样
这样,我们就可以引入引用作返回值的用法
第二点,进行赋值操作,我们举一个例子
比如创建一个结构体数组
#define n 10
typedef struct array
{
int a[n];
int size;
}ay;
然后定义一个取数组数据的函数(引用)
int& PosAt(ay&ay, int i)
{
assert(i < n);
return ay.a[i];
}
然后我们给数组赋值并打印
因为PosAt返回的是数组数据的引用,所以是可以进行修改,即可赋值的左值
5.权限保持
指针和引用,赋值/初始化时,权限可以缩小,但不能放大
什么权限:可读可写的权限
权限平移
权限放大
权限缩小
6.小细节
一 临时变量有常量属性
int Count(int n)
{
n++;
return n;
}
int main()
{
//函数返回值,是创建临时变量
//临时变量有常量性,不能用变量作常量的别名
int& ret = Count();//错误
const int& ret = Count();//正确,改成const就可以
}
二 显示/隐式转换
auto自动推导类型
1.语法
auto可以自动推导新变量的数据类型
2.应用场景
我们在数据结构的学习中会发现,结构体名称可能较长,每次定义新变量的时候不是很方便,所以auto可以缓解这一不便
3.举例
PS:map和string都是以后要学得STL,在此只是举例有很长的类型名,auto可以做相应简化
4.auto遍历数组
int arr[] = { 1,2,3,4,5,6,6,4 };
//原始版
for (int i = 0; i < sizeof(arr) / sizeof(int); i++)
{
cout << arr[i] << " ";
}
cout << endl;
//范围for -- 语法糖
//自动依次获取数组中数据赋值给g对象,自动判断结束
for (auto g : arr)
{
cout << g << " ";
}
cout << endl;
//一样的
for (int x : arr)
{
cout << x << " ";
}
cout << endl;
5.小细节
可以使auto指代更精确
内联函数
1.发明原因
C语言中,宏是一个重要工具。宏常量和宏函数的运用也较为重要
C++中,使用const和enum代替宏常量,而使用内联函数来代替宏函数
宏函数因为在预处理时进行替换,所以不用建立栈帧
同时,我们知道宏函数因其暴力替换的性质,可简化代码,提高复用性的同时也可能带来很多麻烦,或者使事情更复杂
比如 加法的宏函数
#define Add(x,y) ((x)+(y))
左边的多个括号让很多人一头雾水
因其暴力替换的属性,少任何括号都可能产生歧义
例如
#define Add(x,y) x+y
Add(1,2)*3 -->1+2*3
#define Add(x,y) (x+y)
Add(a||b,a&&b) -->a||b+a&&b //但是+比||和&&的优先级高
所以宏函数有时也会添麻烦
而内联函数同样也不需要建立栈帧,而是直接在调用部分展开
2.小细节
一 内联函数是否展开
二 内联函数的分文件编写
三 类内成员函数定义
在类内定义的成员函数,编译器可能会将其定为内联函数(看其是否经常调用且短小)
所以一些经常调用的,短小的,非递归的成员函数,可以直接在类内进行定义
NULL和nullptr
二者都代表0
但是不知道为什么在C++中,NULL的定义时int
这导致NULL的很多功能失效,所以打了nullptr这个补丁,nullptr=(void)0;*