2 C++引用
文章目录
2.1 引用定义和使用
背景:
-
普通类型: char、bool、int、float 等基本类型的数据,内存小,内存拷贝快速。
-
聚合类型:数组、结构体、对象是一系列数据的集合,《聚合类型》数据的数量没有限制,可能很少,也可能成千上万,对它们进行频繁的内存拷贝可能会消耗很多时间,拖慢程序的执行效率。
-
C/[C++] 禁止在函数调用时直接传递数组的内容,而是强制传递数组[指针],对结构体和对象没有限制,推荐使用指针
-
C++在C语言基础上扩充了引用,款姐传递聚合类型。
定义:引用就是变量的别名,和原来变量名一样。类似快捷方式,引用和被引用对象指代同一块内存
注意事项:
- 引用必须在定义时初始化,不能二次初始化,但可以再被赋值,类似常量。<引用指向必须从一而终,不能再引用其它数据>
- 引用和被引用的对象地址相同,引用就是变量别名,没啥区别。
#include <iostream>
using namespace std;
int main() {
int a = 99;
int b=88;
int &r = a;
int &r=b;//,引用无法再初始化
r=b;//正确,r还是a的别名,但是相当于a=r=88;
cout << a << ", " << r << endl;
cout << &a << ", " << &r << endl;
return 0;
}
运行结果:
99, 99
0x28ff44, 0x28ff44
1.引用作为函数参数
类似指针,可以修改实参。
通过引用参数产生的效果同按地址传递是一样的。引用的语法更清楚简单。
2.引用作为参数返回值
1. 作为左值
2. 不可以返回局部变量引用,因为局部变量已经被销毁。
三种数据交换的方式
- 普通数据交换
- 指针数据交换
- 引用数据交换
2.2 常量引用
**作用:**常量引用主要用来修饰形参,防止误操作
本质:
将常引用绑定到临时数据时,
const int &A=10;
编译器会为临时数据创建一个新的、无名的临时变量,并将临时数据放入临时变量中,然后再将引用绑定到临时变量。传参数时创建临时变量,里面通过引用的改变都是对临时变量的改变
注意事项:
- 普通引用不能通过常量初始化。引用需要一个合法的内容空间,然后打上别名。
- 常量引用可以通过常量初始化。编译器创建临时变量
//引用使用的场景,通常用来修饰形参
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;
}
2.3 引用本质
基本概念
指针:
- 指针从本质上讲就是存放变量地址的一个变量,逻辑上与原变量独立,可改变(指针指向对象地址可变,指针所指向的数据可变)
引用:
- 引用是一个变量的别名,存放的被引用对象地址,逻辑上不是独立的,依附原来的变量,所以引用必须在一开始就被初始化,而且其引用的对象在其整个生命周期中是不能被改变的(自始至终只能依附于同一个变量)
参数传递
指针传递:
- 指针参数传递本质上是值传递,它所传递的是实参的地址值,形参作为局部变量,开辟内存。
- 值传递特点,形参的改变不会影响形参的改变
引用传递
- 引用参数传递本质是引用传递,形参作为局部变量开辟地址空间,存放实参地址,被调函数对形参(本体)的任何操作都被处理成间接寻址。
指针传递和引用传递的异同点
- 同:都是被调函数在函数栈空间上的一个局部变量
- 不同:对引用的处理将会通过间接寻址方式影响实参。如果改变被调函数中的指针地址,它将影响不到主调函数的相关变量
指针和引用的异同点
编译角度
-
程序在编译时分别将指针和引用添加到符号表上,符号表上记录的是变量名及变量所对应地址。
-
指针变量在符号表上对应的地址值为指针变量的地址值,
-
而引用在符号表上对应的地址值为引用对象的地址值。符号表生成后就不会再改,
因此指针可以改变其指向的对象(指针变量中的值可以改),而引用对象则不能修改。
-
同:
- 都是地址的概念,指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。
不同:
- 指针是实体,引用是别名
- 引用只能在定义时被初始化一次,之后不可变,引用“从一而终”;指针可变;,指针可以“见异思迁”;
- 指针可以为空,引用不可以为空
- “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小;
- 引用和指针,++的意义不一样
- 引用是类型安全的,而指针不是 (引用比指针多了类型检查)
2.4引用的指向
- 引用只能绑定内存中的数据
- 引用无法绑定临时变量
- 引用不能指向常量表达式
2.4.1引用只能绑定内存中的数据
2.4.2引用无法绑定临时变量
C++临时变量
- 临时变量通常在函数参数传递发生类型转换以及函数返回值时被创建。并不是类似函数交换时创建的一个辅助变量,临时变量往往是无法看见的
void uppercasify(const string& str)
{
}
void uppercasify(string& str) // 参数类型改为string &
{
}
int main(int argc, char* argv[])
{
char subtleBookPlug[] = "Effective C++";
uppercasify(subtleBookPlug); // 此处有类型转换
return 1;
}
- 对于const,函数调用,类型转换,产生一个string的临时变量,str指向临时变量。实参本就无法修改
- 对于非const,str指向的是临时变量,容易让编程人员觉得实参可以修改引起误操作。
2.4.3引用不能指向常量表达式
对于常量表达式,比如
100、3.14*3、7+8、5/3等不包含变量的表达式
常量表达式在编译阶段就能求值。编译器不会分配单独的内存来存储常量表达式的值,而是将常量表达式的值和代码合并到一起,放到虚拟空间的代码区。常量表达式的值虽然在内存中,但是没办法寻址,所以不能用==&==符号来获取地址,也不能用指针指向它。
2.4 引用重载
可基于函数的引用形参是指向 const 对象还是指向非 const 对象重载
class D
{
public:
void f(int &i) { std::cout<<“3”;}; //函数3;
void f(const int &i){ std::cout<<“4” ;};//函数4
};
int main()
{
const int a=0;
f(a)//调用const
int a=0;
f(a)//调用非const
}
。