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