引用
1.概念
引用是变量的别名,编译器不需要为引用变量分配内存空间。
2.语法
数据类型 &别名 = 原名;
注:这里的 "&" 实际上是运算符重载。
下面定义一个整型变量 ,并为它起了3个别名。通过调取内存我们可以发现,a, b, c所指向的是同一块内存空间。
int a = 10;
int &b = a;
int &c = a;
int &d = b;
cout << &a << endl;
cout << &b << endl;
cout << &c << endl;
return 0;
输出结果
引用类型 必须和引用 实体 是 同种类型 的,下面 code 编译报错。
int a = 10;
double &b = a;
3.性质
3.1 一个变量可以有多个引用
具体可见上述 code
3.2 引用在定义的时候必须初始化
int& d;//错误,未初始化
3.3 一旦引用一个实体,再不能引用其他实体
下面 code 编译报错
int main(void) {
int a = 10;
int b = 20;
int& c = a;
&c = b; // 表达式必须是一个可修改的左值
return 0;
}
3.4 引用原则
下面 code 编译报错, 无法从“const int”转换为“int &”
const int x = 20;
int& y = x;
引用原则:对原变量的引用,权限不能放大,但是可以缩小或者不变。
x 是const常量,只读。而引用类型int,可读可写。这就造成了对原变量的权限放大。
const int x = 20;
const int& y = x;//不变
int c = 30;
const int& d = c;//缩小
常量引用
int main() {
//int& ref = 10; 引用本身需要一个合法的内存空间,因此这行错误
//加入const就可以了,编译器优化代码,int temp = 10; const int& ref = temp;
const int& ref = 10;
//ref = 100; //加入const后ref只读,不可以修改变量
cout << ref << endl;
system("pause");
return 0;
}
函数引用传参,可以加const修饰形参,防止引用在函数体内被改变。
void showValue(const int& v) {
//v += 10;
cout << v << endl;
}
int main() {
//函数中利用常量引用防止误操作修改实参
int a = 10;
showValue(a);
system("pause");
return 0;
}
4.使用场景
4.1 函数引用传参
经典的Swap函数,按引用传参。
void Swap(int& x, int& y)
{
int tmp = x;
x = y;
y = tmp;
}
int main()
{
int a = 0, b = 1;
Swap(a, b);
return 0;
}
C++中的swap函数无需引用头文件。只需要#include <iostream>
引用传参的优点就是减少拷贝。
下面code以引用传参为例,比较和按值传参的效率差异。按引用返回同理。
4.3 函数按引用返回
不要返回局部变量引用
函数调用作为左值
//返回局部变量引用
int& test01() {
int a = 10; //局部变量
return a; //存放在栈
}
//返回静态变量引用
int& test02() {
static int a = 20;// 静态变量,存放在全局区
return a;
}
int main() {
//不能返回局部变量的引用
int& ref = test01();
cout << "ref = " << ref << endl; // 10,编译器做了保留
cout << "ref = " << ref << endl; // 乱码,a的内存已经释放
//如果函数做左值,那么必须返回引用
int& ref2 = test02();
cout << "ref2 = " << ref2 << endl; // 20
cout << "ref2 = " << ref2 << endl; // 20
test02() = 1000; //如果函数的返回值是引用,这个函数的返回值可以作为左值
cout << "ref2 = " << ref2 << endl; // 1000
cout << "ref2 = " << ref2 << endl; // 1000
system("pause");
return 0;
}
5. 指针和引用的区别和联系
区别
1. 内存占用:指针是一个实体,存储某个变量的地址,需要分配内存空间。引用只是变量的别名,编译器不需要为引用变量分配内存空间;
2. 是否能被改变:引用不能为空,在定义的时候必须进行初始化,并且不能够改变(尝试改变时编译阶段报错)。指针在定义的时候不一定要初始化,并且指向的空间可变;
3. 有多级指针,但是没有多级引用,只能有一级引用;
4. 自增运算结果:指针是指向下一个内存块空间,引用为变量值自增;
5. sizeof返回值:引用 是所指向的变量、对象的大小,指针 是指针本身的大小;
6. 访问变量的方式:引用 是直接访问,指针 是间接访问;
7. 函数传参:传指针的实质是传值,值就是指针这个地址;传引用的实质是传变量的地址;
联系
引用底层是通过指针实现的,引用的本质是一个指针常量,即指针所指向内存可改变,指针指向不可改变。