目录
1.什么是引用
2.引用的定义
3.引用的特性
4.引用的使用
4.1引用传参
4.2传引用返回
5.const引用(在引用的定义前用const修饰)
5.1对于引用
5.2对于指针
6.引用&指针
总结
1.什么是引用
引用就是给变量起别名,一个变量可以有多个别名,引用变量不会另辟空间,语法上和被引用的变量公用同一块空间,就像一个人可以有多个称号,所有称号都是再说一个人。
2.引用的定义
类型& 引用别名 =被引用对象;
3.引用的特性
- 引用在定义时必须初始化
- 一个变量可以有多个引用
- 引用一旦引用一个实体就不能再引用其他实体
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
using namespace std;
int main()
{const char* jjxt= "帅哥";const char*& x = jjxt;const char*& bozhu = jjxt;int a = 1;int& b = a;int& c = b;cout << jjxt << endl;cout << xxj << endl;cout << bozhu << endl;//const修饰的字符串没法修改cout << a << endl;cout << b << endl;cout << c << endl;++b;//因为本质是同一块空间里的同一个数据,一变全变cout << a << endl;cout << b << endl;cout << c << endl;return 0;
}
4.引用的使用
引用主要被用于引用传参和做返回值时减少拷贝提高效率,和改变引用对象同时改变被引用对象(功能类似指针)在c++中大部分地方我们用引用代替指针,但是少部分地方任然离不开指针(比如链表,因为引用无法改变指向)。
归根结底是因为引用对和被引用对象公用同一空间 。
4.1引用传参
void Swap(int* rx, int* ry)
{int tmp = *rx;*rx = *ry;*ry = tmp;
}void Swap(int& rx, int& ry)
{int tmp = rx;rx = ry;ry = tmp;
}
swap是典型的传址调用函数,可以用传引用代替。
4.2传引用返回
int& func1()
{int ret = 0;return ret;
}
int main()
{int& x = func1();cout << x << endl;return 0;
}
ret在函数栈帧销毁时,空间已经被系统回收,该空间是否被覆盖(被用于存放其他内容)是未知的,取决于编译器,该函数的返回值是一个ret的一个引用,可以理解为系统给了一个临时的引用变量int& tmp = ret,而引用x又对tmp进行引用,也就是说x和被销毁的ret公用一个空间,这是危险的,毕竟我们不知道ret被销毁后,原空间是什么状态。
运行结果:
int& func1()
{int ret = 0;return ret;
}
int& fun2()
{int y = 123;return y;
}
int main()
{int& x = func1();cout << x << endl;fun2();cout << x << endl;return 0;
}
当我们创建于func1几乎相同的,在vs环境中,编译器将原来用于func1的函数栈帧空间分配给func2,导致原来局部变量ret使用的空间被覆盖,此时再通过别名来访问这个空间,就会发现期望的x值已经发生改变。
上述情况是基于被引用对象随着函数栈帧销毁而销毁的情况,这种情况不推荐使用传引用返回,那么反之,当被引用对象不会随着函数栈帧的销毁而销毁时,传引用返回的使用就会使函数更加便捷和灵活,我们推荐使用传引用返回。
对于顺序表中,查找和修改指定位置的函数,利回就用传引用返能合二为一
这时SLat函数独自就能完成读写的操作。
5.const引用(在引用的定义前用const修饰)
被const修饰的对象具有常性,只能读,不能写,也就是访问权限缩小(一般权限的放大缩小是对引用和指针来说的)
对于const修饰的对象,必须用const引用
对于普通对象,const引用也能引用
这是因为,访问权限在引用的过程中只能缩小不能放大。
5.1对于引用
int main()
{const int a = 0;int& ra = a;return 0;
}
这里就会报错,权限被放大了。
5.2对于指针
int main()
{const int a = 0;int& ra = a;int b = 0;const int* p = &b;int* p2 = p;return 0;
}
指针的访问权限被放大,所以报错。(这里多提一点,被const修饰的指针,是它指向的变量具有常性,而不是指针本身具有常性)。
综上所述,我们可以知道,在用引用传参是尽量加上const,这样不管被引用对象是否被const修饰,都可以进行传参。
5.3类型转换中的常性
和函数返回时,产生临时变量一样,类型转换也会产生临时变量。
产生的临时变量为指定的类型且具有常性的。而跨类型引用本质上是对临时变量的引用
int main()
{int i = 0;double& ri = i;int i = 0;const double& ri = i;
}
这里的引用,本质上是对具有常性的double类型的临时变量的引用。
6.引用&指针
- 语法概念上,引用是给一个变量取别名,不开新空间,指针是直接创建一个指针变量来存地址,需要开辟空间。
- 语法上,引用在定义时就要初始化,指针在语法上不强求。
- 引用一旦确定被引用对象就不能更改,指针可以不断改变指向的对象。
- 引用可以直接访问被引用对象,而指针需要解引用。
- sizeof的含义不同,引用是被引用对象的类型大小,指针是地址所占字节个数,32位是4,64位是8。
- 指针很容易出现野指针问题,引用相对安全一些。
二者在实践中有重叠性,但又各有千秋,它们相辅相成,互相不可完全替代。
总结
基本概念
引用是为变量创建的别名,与被引用变量共享内存空间。一个变量可拥有多个引用
核心特性
1. 必须初始化
2. 可多级引用(一个变量多个别名)
3. 一旦绑定实体后不可更改引用对象
主要用途
1. 函数参数:替代指针实现传址调用,更安全简洁
2. 返回值:避免拷贝开销,但需注意返回局部变量引用的风险
const引用
遵循"权限不放大"原则:const对象必须用const引用,普通对象可用const引用
类型转换时会生成具有常性的临时变量
与指针对比
1. 内存:引用不占额外空间,指针需要存储地址
2. 安全性:引用更安全,不存在野引用问题
3. 灵活性:指针可重定向,引用一旦绑定不可更改
4. 访问方式:引用直接访问,指针需解引用
本质区别:引用是语法层面的别名机制,指针是底层的内存地址操作。两者在C++中互补使用,各有适用场景