2025-11-03 18:50:24引用变量基础知识
目录
一、什么是引用变量
二、创建引用变量
三、引用的特性
1、 变量与引用变量它们共同指向相同的值和内存空间地址
2、 引用在声明时必须将其初始化
3、引用一旦建立了引用关系,将一直效忠,不能改变
四、引用变量作为函数的参数
五、引用作为函数的返回值
六、const引用
1、权限问题
2、临时变量
3、函数参数为引用时尽量使用 const
七、指针和引⽤的关系
本人在这篇简单讲⼀下引用变量基础知识,还有⼀些内容等我深入学习后会进行补充,如果有错误,还望大家指出,谢谢!
一、什么是引用变量
C++中新增了一种复合类型——引用变量,C语言中是没有的引用是一个已经定义的变量的别名,编译器不会为引⽤变量开辟内存空间, 变量和引⽤的变量共⽤同⼀块内存空间引用变量主要用途在于作为函数的形参使用,可以减少拷⻉提⾼效率
总体而言引用是C++中不可缺少的部分,也是一种非常方便的类型
二、创建引用变量
C和C++都使用【&】符号表示变量的地址,C++为【&】符号新增了另外一种含义——将其用来声明引用变量
类型& 引⽤别名 = 引⽤对象
int main()
{
//声明变量
int num = 0;
//声明引用变量
int& reference = num;
//声明指针变量
int* pnum = #
//声明引用指针变量
int*& preferrnce = pnum;
//打印
cout << num << endl;
cout << reference << endl;
reference++;
//打印
cout << num << endl;
cout << reference << endl;
//打印地址
cout << &num << endl;
cout << &reference << endl;
return 0;
}
结果:
三、引用的特性
变量与引用变量它们共同指向相同的值和内存空间地址引用在声明时必须将其初始化引用一旦与某一个变量建立了引用关系,将一直效忠,不能改变
1、 变量与引用变量它们共同指向相同的值和内存空间地址
int main()
{
//声明变量
int num = 0;
//声明引用变量
int& reference = num;
//声明指针变量
//打印
cout << num << endl;
cout << reference << endl;
reference++;
//打印
cout << num << endl;
cout << reference << endl;
//打印地址
cout << &num << endl;
cout << &reference << endl;
return 0;
}
由该代码的结果可以观察的变量与引用变量们共同指向相同的值和内存空间地址。引用变量改变的同时变量也随之改变了。这样看上去好像与指针相同了,但实际上它们之间还是有区别的
2、 引用在声明时必须将其初始化
int main()
{
//声明变量
int num = 0;
//声明引用变量
int& reference = num;
//声明指针变量
int* pnum = #
//引用在声明时必须将其初始化,指针可以不用必须初始化
int p = 0;
int& rp;
rp = p;//这样是不行的,会报错
return 0;
}
结果:
3、引用一旦建立了引用关系,将一直效忠,不能改变
引用更加接近【const】修饰的指针,声明时必须初始化, 一旦与某一个变量建立了引用关系,将一直效忠,不能改变
int main()
{
//声明变量
int num = 0;
//声明引用变量
int& reference = num;
//声明指针变量
//这里的 pnum 与 refecence 的作用相同
int* const pnum = #
//打印值
cout << num << endl;
cout << reference << endl;
//打印地址
cout << &num << endl;
cout << &reference << endl;
int num2 = 10;
//改变 refecence 的指向
reference = num2;
//打印值
cout << num << endl;
cout << reference << endl;
cout << num2 << endl;
//打印地址
cout << &num << endl;
cout << &reference << endl;
cout << &num2 << endl;
return 0;
}
结果:
可以观察到【referecence】试图改变指向,从而指向【num2】,作为【num2】的引用变量。从输出值的结果来看,好像成功了,但是【referecence】还是与【num】的地址相同,【referecence】与【num2】的地址不相同
因此引用一旦与某一个变量建立了引用关系,将一直效忠,不能改变
四、引用变量作为函数的参数
引用常用于函数的参数,使得函数中的变量名成为调用函数的中的变量的别名。按引用传参可以使得函数中的变量修改影响到调用函数中的变量,按值传递函数中的变量只是调用函数中变量的值拷贝
交换两个变量的值函数的三种实现:
//值传递
void swap1(int x, int y)
{
int tmp = x;
x = y;
y = tmp;
}
//指针传递
void swap2(int* x, int* y)
{
int tmp = *x;
*x = *y;
*y = tmp;
}
//引用传递
void swap3(int& x, int& y)
{
int tmp = x;
x = y;
y = tmp;
}
int main()
{
int x = 1;
int y = 10;
//值传递
swap1(x, y);
cout << x << " " << y << endl;
x = 1;
y = 10;
//指针传递
swap2(&x, &y);
cout << x << " " << y << endl;
x = 1;
y = 10;
//引用传递
swap3(x, y);
cout << x << " " << y << endl;
return 0;
}
正如结果所示,指针传递与引用传递成功交换了两个变量的值,而值传递没有交换两个变量的值
值传递函数中的变量只是调用函数中变量的值拷贝,函数中变量的变化不会影响到调用函数中指针传递与引用传递的本质操作的都是地址,使得函数中的变量修改影响到调用函数中的变量
五、引用作为函数的返回值
先看一下这段代码:
//函数将返回数组中 pos 位置数
int test1(int* arr, int pos)
{
return arr[pos];
}
int& test2(int* arr, int pos)
{
return arr[pos];
}
int main()
{
int arr[] = {1,2,3,4,5,6,7,8,9};
//只是模拟一个使用场景
//在 pos 位置加一个数
test2(arr, 0) += 10;
cout << arr[0] << endl;
//只是模拟一个使用场景
//在 pos 位置加一个数
test1(arr, 0) += 10;
cout << arr[0] << endl;
return 0;
}
test1结果:
【test1】的返回值不是直接返回【arr [pos] 】的位置,而是先通过临时对象者寄存器等一些临时对象存起来,然后返回这个临时对象, 而这些临时对象都具有常性都是不可以改变的,因此会报【左操作数必须为左值】的错误
test2结果:
【test2】是引用返回,因此不需要生成临时对象存储返回的值,返回的是返回对象的别名,返回的就是返回对象本身
【注意】
引用返回不能返回函数内部在栈上开辟的空间,因为这样会导致一个野引用问题。函数内部开辟的空间在函数结束后就会销毁,不属于程序了
因此引用返回一定要返回不属于函数内部在栈上开辟的对象
错误示范:
//错误示范
//引用返回一定要返回不属于函数内部在栈上开辟的对象
int& test3(int* arr, int pos)
{
int ans = arr[pos];
return ans;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9 };
//只是模拟一个使用场景
//在 pos 位置加一个数
test3(arr, 0) += 10;
cout << arr[0] << endl;
return 0;
}
引⽤返回值的场景相对⽐较复杂,我在这⾥简单讲⼀下场景,还有⼀些内容等我深入学习后会进行补充
六、const引用
1、权限问题
C++在对对象访问权限引⽤过程中规定:
权限不能放大权限可以平移权限可以缩小
int main()
{
//例子1-权限不能放大
const int num1 = 1;
//这里就涉及到权限的放大
int& test1 = num1;
//例子2-权限可以平移
const int num2 = 1;
const int& test2 = num2;
//例子3-权限可以缩小
int num3 = 1;
const int& test3 = num3;
}
【例子1】这里涉及到权限的放大,变量本身被【const】修饰具有常性不可以被修改,而被引用变量引用后,可以修改了,这样很明显是不合理的【例子2】这里是权限的平移,变量本身被【const】修饰具有常性不可以被修改,被引用变量引用后,引用变量也被【const】修饰具有常性不可以被修改,双方都不可以修改,这样是合理的【例子3】这里是权限的缩小,变量本身不具有常性可以以被修改,被引用变量引用后,引用变量被【const】修饰具有常性不可以被修改,但是这并不影响变量本身还是不具有常性可以被修改,这样是合理的
2、临时变量
首先我们要清楚这里的临时变量只存在于内存当中,用于数据之间的过渡,它们通常是寄存器,内存中的一块空间等。但它们都有一个特点:
这些临时变量都是存储在内存当中,我们是不可以随意修改内存中的数值,因此它们都具有常性不可以被修改
可能产生临时变量的情况:
为一个变量赋值变量类型的不匹配运算符运算后的结果
int main()
{
//为一个变量赋常数时会产生临时变量
int test1 = 10;
//变量类型不匹配时会产生临时变量
int num = 10;
double test2 = num;
//运算符运算后的结果会产生临时变量
int test3 = num * 10;
return 0;
}
一下这些引用变量都是不可以的:
int main()
{
//权限的放大
int& r1 = 10;
//权限的放大
int num = 10;
double& r2 = num;
//权限的放大
int& r3 = num * 3;
return 0;
}
这里我们就不难理解了,它们都需要创建临时变量, 而临时变量都是存储在内存当中,我们是不可以随意修改内存中的数值,因此它们都具有常性不可以被修改,而被引用变量引用后,可以修改了,这样很明显是不合理的,其主要原因就是权限的放大
这里我们只需要在引用变量前加上【const】修饰,让它们构成权限的平移,这样就不会有问题了
int main()
{
//权限的平移
const int& r1 = 10;
//权限的平移
int num = 10;
const double& r2 = num;
//权限的平移
const int& r3 = num * 3;
return 0;
}
3、函数参数为引用时尽量使用 const
通过上面的展开,我们可以了解到引用有很强的指向性,引用变量的类型就决定了变量的类型,而我们函数引用具有很强的不确定性,我们也不知道可能会传递过来一个什么样的形参,为了减少这种不确定性, 函数参数为引用时尽量使用 const
函数参数为引用时尽量使用【const】的理由:
使用【const】 可以避免无意中修改数据的编程报错使用【const】使函数能够处理【const】和非【const】实参,否则只能接受非【const】数据使用【const】引用使函数能够正确生成并使用临时变量
七、指针和引⽤的关系
C++中指针和引⽤就像两个性格迥异的亲兄弟,指针是哥哥,引⽤是弟弟,在实践中他们相辅相成,功能有重叠性,但是各有⾃⼰的特点,互相不可替代
语法概念上引⽤是⼀个变量的取别名不开空间,指针是存储⼀个变量地址,要开空间引⽤在定义时必须初始化,指针建议初始化,但是语法上不是必须的引⽤在初始化时引⽤⼀个对象后,就不能再引⽤其他对象;⽽指针可以在不断地改变指向对象引⽤可以直接访问指向对象,指针需要解引⽤才是访问指向对象sizeof中含义不同,引⽤结果为引⽤类型的⼤⼩,但指针始终是地址空间所占字节个数(32位平台下占4个字节,64位下是8byte) 指针很容易出现空指针和野指针的问题,引⽤很少出现,引⽤使⽤起来相对更安全⼀些