1.C++ 引用:
一.定义
在 C++ 中,引用是给已存在的变量起的一个别名。引用不是一个新的变量,它与被引用的变量共用同一块内存空间。
二.声明
引用的声明使用 & 符号,例如: int& ref = num; ,这里 ref 就是变量 num 的引用。
三、特点
引用必须在创建时初始化,且一旦初始化,就不能再指向其他变量。
引用在使用时和被引用的变量完全等价,对引用的操作就是对被引用变量的操作。
四、和指针的区别
1.引用在语法层面不开辟空间只是对变量取别名
指针在语法层面开辟空间存放变量
但是从底层汇编的角度看,引用是通过类似指针的方式实现的!
2.引用在声明时必须初始化,而指针可以在任何时候赋值。
3.引用一旦与某个变量绑定,就不能再改变指向,指针则可以随时改变指向。
4.引用没有 NULL 引用,而指针可以为 NULL 。
6.引用在sizeof的结果为引用类型的大小,而指针在sizeof的结果是地址空间所占的大小。
7.引用++表示引用的实体的值+1,而指针+1是指针像后偏移一个类型的大小
五、引用的注意事项
引用不能引用引用,不能引用数组。(引用无法完全替代指针!)但指针也可以取别名
引用的类型必须与被引用变量的类型一致。
我们用引用可以去写一个交换两个数和交换两个指针的函数
//交换两个数
void swap(int&a,int&b)
{
int tmp = a;
a = b;
b = tmp;
}
//交换两个指针
void swap(int*& a, int*& b)
{
int* tmp = a;
a = b;
b = tmp;
}
当然一个数的引用可以有多个,但是它们的地址都是一样的,并且只要其中一个的值改变,其他的值都会改变,并且改变后一致!
同一个域里面不能出现同名!会有歧义
但是不同的域可以!
引用不会去额外开辟空间
2.引用被当作参数
1:(输出型参数)
2.(提高效率)(大对象/深拷贝对象)
3.引用用作返回值
int back(void)
{
return 3;
}
int main(void) {
int a = back();
return 0;
}
这个返回值3是直接给a的吗?
显然不是,编译器会生成一个临时变量(不一定是寄存器,因为寄存器一般是四个字节或者八个字节)
作为back()的返回值,给予a
要临时变量去存放这个3,因为这个3的作用域是在back函数内,出函数就会销毁掉!
那如果我用static呢?
毕竟static修饰的变量存放在静态区,不会因函数销毁而销毁
编译器没有对static专门去处理,也需要一个临时变量去储存,那么有没有不需要临时变量的方式呢?
显然有,就是引返回值用引用(减少拷贝提升效率),比如像下面这样
int& back(void)
{
static int a = 5;
a++;
return a;
}
但是这个地方还需要注意的是,当函数结束后,返回值要还存在,才可以引用返回值,不然就可能造成非法访问!
比如上面用的static修饰的a,是在静态区上,当函数结束后依然存在,不会随着函数栈帧的销毁而销毁,包括全局变量和malloc,realloc的变量都是可以使用引用返回值的!
4.常引用
使用引用的时候,引用的权限可以平移缩小,但是不能变大
比如说上面这串代码,为什么会报错?
因为我们返回的是static修饰的变量,返回的时候要先创建临时变量,再把这个临时变量赋给a,
但是临时变量是具有常性,即(const不可修改性) ,但是&a是可修改性的,从不可改变性变成可改变性权限扩大了,但是引用的权限只能平移或者缩小,因此我们这个地方可以在int&a前面加一个const就行了
就像这样
int back1(void)
{
static int a = 5;
a++;
return a;
}
int main(void) {
const int &a= back1();
return 0;
}
这个时候引用的权限就算平移了
但是为啥我们在这个地方这样也可以
//返回常量
int back1(void)
{
static int a = 5;
a++;
return a;
}
int main(void) {
int a= back1();
return 0;
}
因为这个地方我们本质并不是引用,而是把返回值拷贝过来了,而且这个地方我们没有涉及到引用,自然就不用去考虑权限的扩大缩小和平移了!,下图同理
//返回引用
int& back2(void)
{
static int b = 6;
b++;
return b;
}
int main(void) {
int a= back2();//拷贝
int& b = back2();//权限平移
const int& c = back2();//权限缩小
return 0;
}
需要注意的是,不同类型的变量的转换也需要创建临时变量
我们前面说过什么?临时变量具有常性,因此这个地方会非常容易错
int main(void) {
double a = 1.1;
// const int& b = a;//不会报错 权限平移
int& b = a;//会报错 权限扩大了
return 0;
}