C++ 黑马 引用
一, 引用的基本概念
前言:由于VS2022过去先进,所以有很多的东西是错误的,但是VS2022编译器会自动优化,所以学习的话推荐使用Dev-C++,版本较老,当我们步入项目的时候就可以避免很多的错误,再使用VS2022也不迟
引用的作用: 给变量起别名
语法: 数据类型 &别名 = 原名
示例:
#include<iostream>using namespace std;int main() {int a = 10;int &b = a;cout << "a = " << a << endl;cout << "b = " << b << endl;b = 100;cout << "a = " << a << endl;cout << "b = " << b << endl;system("pause");return 0;
}
编译输出:
a = 10
b = 10
a = 100
b = 100
请按任意键继续. . .
得出的结果是,可以利用去修改它指向的变量,类似于指针一样的操作
二, 引用的注意事项
1 引用需要进行初始化
2 引用初始化之后,就不可以改变
int main() {int a = 10;int b = 20;//int &c; //错误,引用必须初始化int &c = a; //一旦初始化后,就不可以更改c = b; //这是赋值操作,不是更改引用cout << "a = " << a << endl;cout << "b = " << b << endl;cout << "c = " << c << endl;system("pause");return 0;
}
当我们直接去初始化的时候,编译器是会给我们直接报错的
所以在运用引用的时候一定要先进行初始化,然后再使用
再使用的同时,赋值不是改变它的朝向,而是改变它指向的变量的值
三, 引用做函数的参数
作用:函数传参时,可以利用引用的技术让形参修饰实参
优点:可以简化指针修改实参
示例代码:
//1. 值传递
void mySwap01(int a, int b) {int temp = a;a = b;b = temp;
}//2. 地址传递
void mySwap02(int* a, int* b) {int temp = *a;*a = *b;*b = temp;
}//3. 引用传递
void mySwap03(int& a, int& b) {int temp = a;a = b;b = temp;
}int main() {int a = 10;int b = 20;mySwap01(a, b);cout << "a:" << a << " b:" << b << endl;mySwap02(&a, &b);cout << "a:" << a << " b:" << b << endl;mySwap03(a, b);cout << "a:" << a << " b:" << b << endl;system("pause");return 0;
}
编译输出:
a:10 b:20
a:20 b:10
a:10 b:20
请按任意键继续. . .
参数的形式就是类似于变量的形式:int& a;
总结:通过引用参数产生的效果同按地址传递是一样的。引用的语法更清楚简单
三,引用用做函数的返回值
作用:引用是可以作为函数的返回值存在的
注意:不要返回局部变量引用
用法:函数调用作为左值
//返回局部变量引用
int& test01() {int a = 10; //局部变量return a;
}//返回静态变量引用
int& test02() {static int a = 20;return a;
}int main() {//不能返回局部变量的引用int& ref = test01();cout << "ref = " << ref << endl;cout << "ref = " << ref << endl;//如果函数做左值,那么必须返回引用int& ref2 = test02();cout << "ref2 = " << ref2 << endl;cout << "ref2 = " << ref2 << endl;test02() = 1000;cout << "ref2 = " << ref2 << endl;cout << "ref2 = " << ref2 << endl;system("pause");return 0;
}
编译器输出:
ref = 10
ref = 0
ref2 = 20
ref2 = 20
ref2 = 1000
ref2 = 1000
请按任意键继续. . .
第一个test01表示的当局部变量这样的生命周期很短的,当我们运用引用的返回值来进行操作的时候,会导致引用最后分配失败
第二个test02表示的是引用是可以充当左值的,就比如我们函数返回值为一个引用,然后我们直接用这个函数名字赋值就是可以把这个值改变
四, 常量引用
作用:常量引用主要用来修饰形参,防止误操作
在函数形参列表中,可以加const修饰形参,防止形参改变实参
示例:
//引用使用的场景,通常用来修饰形参
void showValue(const int& v) {//v += 10;cout << v << endl;
}int main() {//int& ref = 10; 引用本身需要一个合法的内存空间,因此这行错误//加入const就可以了,编译器优化代码,int temp = 10; const int& ref = temp;const int& ref = 10;//ref = 100; //加入const后不可以修改变量cout << ref << endl;//函数中利用常量引用防止误操作修改实参int a = 10;showValue(a);system("pause");return 0;
}
这里有两个知识点:
1 当我们给一个常量引用赋值一个数值的时候,这个时候编译器会创建一个临时的局部变量存储这个数值,然后这个常量引用会指向这个变量
2 当我们设置了常量引用的时候,指向的值是不可以进行更改的,当我们传参的时候就可以很好的运用这个一个点,对我们的数值进行很好的保护,防止值不会被进行更改
对于第一个知识点,《C++primer plus》有额外的例子进行叙述
当我们去函数传参的时候,传入的是一个表达式的时候,这个时候编译器会创建一个临时的变量去保存这个值,然后这个常量引用会指向这个创建的临时变量
编译器都将生成一个临时匿名变量,并让引用变量指向它。这些临时变量只在函数调用期间存在,此后编译器便可以随意将其删除
除此之外,C++primer plus还举例了另外一个知识点
3 使用 const使函数能够处理 const和非 const 实参,否则将只能接受非 const数据
void processConst(const int& x) {} // 能接受const和非const实参
void processNonConst(int& x) {} // 只能接受非const实参int main() {int a = 10;const int b = 20;processConst(a); // OK:非const -> const引用processConst(b); // OK:const -> const引用processNonConst(a); // OK:非const -> 非const引用processNonConst(b); // 错误!不能将const转为非const
}
就是当我们传参数的时候const的兼容的更多,但是普通的引用的传参不可以兼容const类型的常量
将引用参数声明为常量数据的引用的理由有三个:
• 使用 const 可以避免无意中修改数据的编程错误
• 使用 const使函数能够处理 const和非 const 实参,否则将只能接受非 const数据
• 使用 const 引用使函数能够正确生成并使用临时变量。 因此,应尽可能将引用形参声明为 const
五 总结:
1 引用的基本概念
引用的基本用法:数据类型& 变量名 = 指向的变量
2 引用的注意事项
(a) 引用在创建的时候就要进行初始化
(b) 引用在初始化之后不可以改变指向
3 引用作为函数的参数与用作返回值
(a) 函数的传参没有指针那么的繁琐,不需要考虑解引用问题,直接使用即可
(b) 函数的返回值为引用的时候,当生存周期较短的时候,不要作为引用
(c) 函数的返回值为引用的时候可以作为左值,引用可以作为左值
4 常量引用
这个知识点主要运用到函数的传参里面
(a) 常量引用指向的值是不可以根据引用进行修改的,那么就可以确保数值的安全性
(b) 当没有明确的变量存储值,然而这个值却用常量引用进行指向的话,编译器会自己创建一个临时的变量
(c) 当传参数的时候const的兼容性会更好