C++引用
C语言中有指针的概念,但是这个指针在某些应用场景下十分的复杂,且效率低下。所以C++语言中提出了引用的概念,来与指针相辅相成。
一、引用的概念和定义
引用不是新定义一个变量,而是给已存在变量取一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用一块内存空间。
类型& 引用别名 = 引用对象;
int a = 10;
int& b = a;
二、引用的特性
这里我们要明确一点C++的引用与其他语言( Java 等)的引用有所不同。下面主要和Java展开区分。
-
引用在定义时必须初始化 ( Java可以不初始化,但是建议直接初始化)
int a = 10; int& b = a; // 必须 //int& c; // 错误
-
一个变量可以有多个引用,且可以引用另一个引用 (这就好比一个人可以有好多个绰号或者小名)
int a = 10; int& b = a; int& c = a; // 一个变量可以有多个引用 int& d = c; // 引用另一个引用
-
引用一旦引用一个实体,再不能引用其他实体 ( Java用引用完全代替指针的概念,可以改变)
int a = 10; int b = 20; int& c = a; c = b; c += 100; cout << a << endl; cout << b << endl; cout << c << endl;
// 结果为: 120 20 120
三、引用的使用
-
引用在实战中主要是于引用传参和引用做返回值中减少拷贝提高效率和改变引用对象时同时改变被引用对象。
void func(vector<vector<int>>& arr); // 减少了拷贝构造的过程,提高时间和空间效率
-
引用传参跟指针传参功能是类似于引用传参相对更方便一些。
// 实现两个数交换功能(采用指针实现) #include <iostream> using namespace std; void Swap(int* p1, int* p2) { int tmp = *p1; *p1 = *p2; *p2 = tmp; } int main() { int a = 10, b = 20; Swap(&a, &b); return 0; }
// 实现两个数交换功能(采用引用实现) #include <iostream> using namespace std; void Swap(int& ra, int& rb) { int tmp = ra; ra = rb; rb = tmp; } int main() { int a = 10, b = 20; Swap(a, b); return 0; }
-
引用做函数返回值的时候(vector容器类似于数组一样的赋值方式)
#include <iostream> #include <vector> using namespace std; int main() { vector<int> arr(10); for (size_t i = 0; i < 10; i++) { arr[i] = i; // 这其实就是用到了运算符重载和引用返回的概念 } return 0; }
-
引用和指针字啊实战中相辅相成,功能有重叠性,但是各有特点,互相不可替代。C++的引用跟其他语言的引用(如 Java )是有很大的区别的,详细可以参考上面引用的特性。
四、const引用
可以引用一个const对象,但是必须用const引用。const引用也可以引用普通对象,因为对象的访问权限在引用的过程中可以缩小,但是不能放大。
#include <iostream>
using namespace std;
int main()
{
int a = 10;
const int& ra = a; // ra只可读不可写,但是不影响变量a的属性。
const int b = 10;
//int& rb = b; // 错误,权限放大
const int& rb = b;
//int& rc = (a * b); // 错误,权限放大。a * b的结果保存在一个临时对象(具有常性)
const int& rc = (a * b);
double d = 12.34;
//int& rd = d; // 同理上面,权限放大。double类型用int引用有出现一个隐式转换,隐式转换的值存在临时对象中
const int& rd = d
return 0;
}
上面代码引入了临时对象的概念。所谓临时对象就是编译器需要一个空间暂存表达式的求值结果时,临时创建的一个未命名的对象,C++中把这个未命名对象叫做临时对象。(临时对象具有常性)
五、指针和引用的关系
C++中指针和引用相辅相成,功能有重叠性,但是各有自己的特点,互相不可替代。但是这里明确引用的底层是通过指针实现的。
- 语法概念上引用是一个变量的取别名不开空间,指针是存储一个变量的地址,要开空间。
- 引用在定义时必须初始化,指针建议初始化,但是语法上不是必须的。
- 引用在初始化时引用一个对象后,就不能再引用其他对象;而指针可以再不断地改变指向对象。
- 引用可以直接访问指向对象,指针需要解引用才是访问指向对象。
- sizeof中含义不同,引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节,64位下是8个字节)
- 指针很容易出现空指针和野指针的问题,引用很少出现,引用使用起来相对更安全一些。
引用在一些方面大大提高代码空间与时间效率,并且使用时更加方便。但是有一些方面是必须采用指针的,比如链表next指针(因为要频繁的增删改查,所以该变量需要不断的改变指向,所以引用不可用)。