关注泷羽Sec-静安 公众号,后台回复 找书+ C++Primer 获取C++相关电子书
C++ 的引用(reference)是一个别名,它为已经存在的变量创建了一个新的名字。引用必须在声明时进行初始化,并且一旦绑定到一个变量,就不能再改变绑定的对象。引用的主要用途是通过函数参数传递和返回值,避免复制大对象,提高程序效率。
引用用法
#include<iostream>// 函数声明,使用引用作为参数voidprintAndModify(int& num){// 输出引用的值std::cout << "原始值: " << num << std::endl;// 修改引用的值 num = 42;}intmain(){// 定义一个整数变量int myNumber = 10;// 创建一个引用,引用变量 myNumber 类型& 别名=被引用的名int& refNumber = myNumber;// 输出原始变量和引用的值std::cout << "myNumber: " << myNumber << std::endl;std::cout << "refNumber: " << refNumber << std::endl;// 修改引用的值 refNumber = 20;// 输出修改后的变量和引用的值std::cout << "修改后的 myNumber: " << myNumber << std::endl;std::cout << "修改后的 refNumber: " << refNumber << std::endl;// 调用函数,传递引用 printAndModify(myNumber);// 输出函数调用后的变量值std::cout << "函数调用后 myNumber: " << myNumber << std::endl;std::cout << "函数调用后 refNumber: " << refNumber << std::endl;return0;}---myNumber: 10refNumber: 10修改后的 myNumber: 20修改后的 refNumber: 20原始值: 20函数调用后 myNumber: 42函数调用后 refNumber: 42
注意事项
-
引用必须初始化:引用在声明时必须进行初始化,否则会导致编译错误。 -
引用不能重新绑定:引用一旦绑定到一个变量,就不能再改变绑定的对象。尝试重新绑定引用实际上是修改引用所指向的变量的值。 -
避免悬空引用:引用的对象在引用的生命周期内必须存在,否则会导致未定义行为。返回局部变量的引用会导致悬空引用,因为局部变量在函数返回后会被销毁,访问悬空引用会导致未定义行为。
1. 引用必须初始化
#include<iostream>intmain(){int myNumber = 10;int& refNumber = myNumber; // 正确:引用在声明时初始化// int& uninitializedRef; // 错误:引用未初始化,会导致编译错误std::cout << "myNumber: " << myNumber << std::endl;std::cout << "refNumber: " << refNumber << std::endl;return0;}
2. 引用不能重新绑定
#include<iostream>intmain(){int myNumber1 = 10;int myNumber2 = 20;int& refNumber = myNumber1; // 引用绑定到 myNumber1std::cout << "refNumber (initially): " << refNumber << std::endl; refNumber = myNumber2; // 这是修改 myNumber1 的值,而不是重新绑定引用std::cout << "refNumber (after assignment): " << refNumber << std::endl;std::cout << "myNumber1 (after assignment): " << myNumber1 << std::endl;return0;}
3. 避免悬空引用
#include<iostream>int& createDanglingReference(){int localVar = 10;return localVar; // 错误:返回局部变量的引用,会导致悬空引用}intmain(){int& danglingRef = createDanglingReference(); // 悬空引用,未定义行为// 访问悬空引用会导致未定义行为,可能会崩溃或输出垃圾值std::cout << "danglingRef: " << danglingRef << std::endl;return0;}
能解除引用吗?
引用一旦绑定到一个变量,就不能再改变绑定的对象,因此引用不能被“解出”或重新绑定到另一个变量。然而,您可以通过使用指针来实现类似的效果,因为指针可以重新指向不同的对象。
#include<iostream>// 函数声明,使用指针作为参数voidprintAndModify(int* num){// 输出指针指向的值std::cout << "原始值: " << *num << std::endl;// 修改指针指向的值 *num = 42;}intmain(){// 定义两个整数变量int myNumber1 = 10;int myNumber2 = 20;// 创建一个指针,指向变量 myNumber1int* ptrNumber = &myNumber1;// 输出原始变量和指针指向的值std::cout << "myNumber1: " << myNumber1 << std::endl;std::cout << "ptrNumber: " << *ptrNumber << std::endl;// 修改指针指向的值 *ptrNumber = 30;// 输出修改后的变量和指针指向的值std::cout << "修改后的 myNumber1: " << myNumber1 << std::endl;std::cout << "修改后的 ptrNumber: " << *ptrNumber << std::endl;// 重新指向另一个变量 ptrNumber = &myNumber2;// 输出重新指向后的变量和指针指向的值std::cout << "myNumber2: " << myNumber2 << std::endl;std::cout << "重新指向后的 ptrNumber: " << *ptrNumber << std::endl;// 调用函数,传递指针 printAndModify(ptrNumber);// 输出函数调用后的变量值std::cout << "函数调用后 myNumber2: " << myNumber2 << std::endl;return0;}---myNumber1: 10ptrNumber: 10修改后的 myNumber1: 30修改后的 ptrNumber: 30myNumber2: 20重新指向后的 ptrNumber: 20原始值: 20函数调用后 myNumber2: 42
引用做函数参数
使用引用作为函数参数,并在函数中修改引用的值。可以编写两个函数来交换数字,一个使用引用作为参数,另一个使用指针作为参数。然后在 main 函数中测试这两个函数的区别。引用传参语法更清楚,更简单,更易于理解。
#include<iostream>// 使用引用作为参数的交换函数voidswapByReference(int& a, int& b){int temp = a; a = b; b = temp;}// 使用指针作为参数的交换函数voidswapByPointer(int* a, int* b){int temp = *a; *a = *b; *b = temp;}intmain(){// 定义两个整数变量int num1 = 10;int num2 = 20;// 输出原始值std::cout << "交换前: num1 = " << num1 << ", num2 = " << num2 << std::endl;// 使用引用作为参数的交换函数 swapByReference(num1, num2);// 输出交换后的值std::cout << "使用引用交换后: num1 = " << num1 << ", num2 = " << num2 << std::endl;// 再次定义两个整数变量 num1 = 10; num2 = 20;// 使用指针作为参数的交换函数 swapByPointer(&num1, &num2);// 输出交换后的值std::cout << "使用指针交换后: num1 = " << num1 << ", num2 = " << num2 << std::endl;return0;}---交换前: num1 = 10, num2 = 20使用引用交换后: num1 = 20, num2 = 10使用指针交换后: num1 = 20, num2 = 10
引用做函数返回值
使用引用作为函数的返回值类型,并确保不返回局部变量的引用。我们将使用一个数组,并编写一个函数来返回数组元素的引用。函数的调用可以作为左值。
#include<iostream>// 返回数组元素的引用int& getElement(int arr[], int index){// 返回数组中指定索引的元素的引用return arr[index];}intmain(){// 定义一个包含5个整数的数组int myArray[5] = {10, 20, 30, 40, 50};// 输出原始数组元素std::cout << "原始数组元素: ";for (int i = 0; i < 5; ++i) {std::cout << myArray[i] << " "; }std::cout << std::endl;// 获取数组中索引为2的元素的引用,并修改其值 getElement(myArray, 2) = 100;// 输出修改后的数组元素std::cout << "修改后的数组元素: ";for (int i = 0; i < 5; ++i) {std::cout << myArray[i] << " "; }std::cout << std::endl;return0;}---原始数组元素: 1020304050修改后的数组元素: 10201004050
引用的本质
引用的本质是指针常量,这意味着引用在底层实现上类似于指针,但它有一些不同的特性。引用在声明时必须初始化,并且一旦绑定到一个变量,就不能再改变绑定的对象。引用的语法更简洁,使用起来更安全。
#include<iostream>// 使用引用作为参数的函数voidmodifyByReference(int& ref){ ref = 42;}// 使用指针作为参数的函数voidmodifyByPointer(int* ptr){ *ptr = 42;}intmain(){// 定义一个整数变量int myNumber = 10;// 创建一个引用,引用变量 myNumberint& refNumber = myNumber;// 创建一个指针,指向变量 myNumberint* ptrNumber = &myNumber;// 输出原始变量、引用和指针的值std::cout << "原始值: " << myNumber << std::endl;std::cout << "引用值: " << refNumber << std::endl;std::cout << "指针值: " << *ptrNumber << std::endl;// 修改引用的值 refNumber = 20;// 输出修改后的变量、引用和指针的值std::cout << "修改引用后的值: " << myNumber << std::endl;std::cout << "引用值: " << refNumber << std::endl;std::cout << "指针值: " << *ptrNumber << std::endl;// 修改指针指向的值 *ptrNumber = 30;// 输出修改后的变量、引用和指针的值std::cout << "修改指针后的值: " << myNumber << std::endl;std::cout << "引用值: " << refNumber << std::endl;std::cout << "指针值: " << *ptrNumber << std::endl;// 使用引用作为参数的函数 modifyByReference(myNumber);// 输出函数调用后的变量、引用和指针的值std::cout << "函数调用后 (引用): " << myNumber << std::endl;std::cout << "引用值: " << refNumber << std::endl;std::cout << "指针值: " << *ptrNumber << std::endl;// 使用指针作为参数的函数 modifyByPointer(&myNumber);// 输出函数调用后的变量、引用和指针的值std::cout << "函数调用后 (指针): " << myNumber << std::endl;std::cout << "引用值: " << refNumber << std::endl;std::cout << "指针值: " << *ptrNumber << std::endl;return0;}---原始值: 10引用值: 10指针值: 10修改引用后的值: 20引用值: 20指针值: 20修改指针后的值: 30引用值: 30指针值: 30函数调用后 (引用): 42引用值: 42指针值: 42函数调用后 (指针): 42引用值: 42指针值: 42
常量引用
通过编写一个交换两个数字的函数来展示常量引用修饰形参防止误操作的用法。我们将分别展示不使用 const 和使用 const 的情况,并说明它们的区别。
#include<iostream>// 不使用 const 的交换函数voidswapWithoutConst(int& a, int& b){int temp = a; a = b; b = temp;}// 使用 const 的交换函数voidswapWithConst(constint& a, constint& b){// 由于 a 和 b 是 const 引用,不能修改它们的值// 这段代码会导致编译错误// int temp = a;// a = b;// b = temp;}intmain(){// 定义两个整数变量int num1 = 10;int num2 = 20;// 输出原始值std::cout << "交换前: num1 = " << num1 << ", num2 = " << num2 << std::endl;// 使用不带 const 的交换函数 swapWithoutConst(num1, num2);// 输出交换后的值std::cout << "使用不带 const 的交换后: num1 = " << num1 << ", num2 = " << num2 << std::endl;// 再次定义两个整数变量 num1 = 10; num2 = 20;// 使用带 const 的交换函数// 这段代码会导致编译错误,因为 swapWithConst 函数不能修改 const 引用的值// swapWithConst(num1, num2);// 输出交换后的值std::cout << "使用带 const 的交换后: num1 = " << num1 << ", num2 = " << num2 << std::endl;return0;}
如果想要用引用的方法又怕不小心改参数怎么办?
#include<iostream>// 不使用 const 的交换函数voidswapWithoutConst(int& a, int& b){int temp = a; a = b; b = temp;}// 使用 const 的交换函数voidswapWithConst(constint& a, constint& b){// 使用临时变量存储 a 和 b 的值int tempA = a;int tempB = b;// 在临时变量上进行操作int temp = tempA; tempA = tempB; tempB = temp;// 输出临时变量的值,验证交换是否成功std::cout << "在 swapWithConst 函数中: tempA = " << tempA << ", tempB = " << tempB << std::endl;}intmain(){// 定义两个整数变量int num1 = 10;int num2 = 20;// 输出原始值std::cout << "交换前: num1 = " << num1 << ", num2 = " << num2 << std::endl;// 使用不带 const 的交换函数 swapWithoutConst(num1, num2);// 输出交换后的值std::cout << "使用不带 const 的交换后: num1 = " << num1 << ", num2 = " << num2 << std::endl;// 再次定义两个整数变量 num1 = 10; num2 = 20;// 使用带 const 的交换函数 swapWithConst(num1, num2);// 输出交换后的值std::cout << "使用带 const 的交换后: num1 = " << num1 << ", num2 = " << num2 << std::endl;return0;}---交换前: num1 = 10, num2 = 20使用不带 const 的交换后: num1 = 20, num2 = 10在 swapWithConst 函数中: tempA = 20, tempB = 10使用带 const 的交换后: num1 = 10, num2 = 20
🔔 想要获取更多网络安全与编程技术干货?
关注 泷羽Sec-静安 公众号,与你一起探索前沿技术,分享实用的学习资源与工具。我们专注于深入分析,拒绝浮躁,只做最实用的技术分享!💻
扫描下方二维码,马上加入我们,共同成长!🌟
👉 长按或扫描二维码关注公众号
或者直接回复文章中的关键词,获取更多技术资料与书单推荐!📚
原文始发于微信公众号(泷羽Sec-静安):11xC++引用
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论