引用
- [1 前情提要](#1 前情提要)
- [2 概念剖析](#2 概念剖析)
- [3 引用特性](#3 引用特性)
- [4 常引用](#4 常引用)
- [5 使用场景](#5 使用场景)
-
- 5.1做参数
- [5.2 做返回值](#5.2 做返回值)
- [6 传值 传引用的效率比较](#6 传值 传引用的效率比较)
- [7 引用与指针的差异](#7 引用与指针的差异)
- Thanks♪(・ω・)ノ谢谢阅读
- 下一篇文章见
1 前情提要
在C语言中,我们往往会遇见复杂的指针(如数据结构之中的二级指针),理解起来比较复杂,C++对此加入了引用的概念。
指针和引用的大部分功能类似,是重叠的。
C++的引用可以在较为复杂的情况下进行一定替换,让代码变得更加简洁
但是不能完全替代指针!!!
2 概念剖析
C++中提出了一个新概念:引用
引用为对象起一个别名 ,与对象使用同一内存空间。
打个比方:孙悟空,又叫孙行者,又叫孙大圣,还叫齐天大圣。这个四个名字都指向同一个人。
我们来看一个样例:
3 引用特性
- 引用在定义时必须初始化
- 一个变量可以有多个引用
- 引用一旦引用一个实体,再不能引用其他实体(与指针相异)
必须初始化
这样写就会报错:
E0252 引用 变量 "b" 需要初始值设定项
对于引用的不可修改性,导致它不能完全替代指针。
就比如链表中,如果将前后指针换位引用,就会导致我们成功进行。
如图的双向链表就不能将中间的链表不能成功删除。因为无法改变引用指向。
4 常引用
cpp
int main() {
const int a = 10;
int& ra = a; // 该语句编译时会出错,a为常量
const int& ra = a;
int& b = 10; // 该语句编译时会出错,b为常量
const int& b = 10;
double d = 12.34;
int& rd = d; // 该语句编译时会出错,类型不同
const int& rd = d;
return 0;
}
引用变量是不可改变的左值
5 使用场景
5.1做参数
我们回想一下C语言的交换函数:
c
void swap(int* pa ,int* pb){
int tmp = *pa;
*pa = *pb;
*pb = tmp;
return;
}
int main(){
int a = 2 ;
int b = 8 ;
swap(&a,&b);
return 0;
}
而再C++中我们不再需要使用指针
cpp
void swap(int& a, int& b) {
int tmp = a;
a = b;
b = tmp;
return;
}
int main() {
int a = 2;
int b = 8;
swap(a, b);
return 0;
}
5.2 做返回值
作为一种数据类型,那一定可以作为返回值来写函数。如下:
cpp
int& Count()
{
//...
//延长生命周期,防止销毁
static int n = 0;
n++;
// ...
return n;
}
来看一段错误使用样例:
cpp
int& Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int& ret = Add(1, 2);
Add(3, 4);
cout << "Add(1, 2) is :"<< ret <<endl;
return 0;
}
来看看运行效果
为什么会出现这种情况???
总的来说,就是地址上储存的值被改变了。
6 传值 传引用的效率比较
以值作为参数或者返回值类型,在传参和返回期间,
函数不会直接传递实参或者将变量本身直接返回,
而是传递实参或者返回变量的一份临时的拷贝,
因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。
而对于传引用操作相当于返回一个"指针",
来看比较:
很明显的效率差异。
7 引用与指针的差异
引用和指针区别:
语法:
- 引用是别名,不开空间 ,指针是地址,需要开空间存地址
- 引用必须初始化 ,指针可以初始化也可以不初始化(最好初始化)
- 引用不能改变指向 ,指针可以
- 引用相对更安全,没有空引用,但是有空指针,容易出现野指针,但是不容易出现野引用
- sizeof、++、解引用访问等方面的区别
- 有多级指针 ,但是没有多级引用
- 访问实体方式不同 ,指针需要显式解引用 ,引用编译器自己处理
- 引用比指针使用起来相对更安全
底层:
汇编层面上,没有引用,都是指针,引用编译后也转换成指针了