C++ 引用 详解

引用

引用 不是新定义一个变量,而 是给已存在变量取了一个别名 ,编译器不会为引用变量开辟内存空
间,它和它引用的变量 共用同一块内存空间。
比如: 李逵 ,在家称为 " 铁牛 " ,江湖上人称 " 黑旋风 "
类型 & 引用变量名 ( 对象名 ) = 引用实体;
引用类型 必须和引用 实体 同种类型
void TestRef()
{
    int a = 10;
    int& ra = a;//<====定义引用类型
    printf("%p\n", &a);
    printf("%p\n", &ra);
}

引用特性

1. 引用在 定义时必须初始化
2. 一个变量可以有多个引用
3. 引用一旦引用一个实体,再不能引用其他实体
void TestRef()
{
   int a = 10;
   // int& ra;   // 该条语句编译时会出错
   int& ra = a;
   int& rra = a;
   printf("%p %p %p\n", &a, &ra, &rra);  
}

一个变量可以有多个引用,对同一块空间的多个外号命名

int main()
{	// int& b; // 引用在定义时必须初始化
	int a = 0;
	int& b = a;
	int& c = a;
	int& d = b;

	int x = 1;
	// 赋值
	b = x;

	return 0;
}

常引用

在引用的过程中
// 权限可以平移
// 权限可以缩小
// 权限不能放大

void TestConstRef()
{
    const int a = 10;
    //int& ra = a;   // 该语句编译时会出错,a为常量
    const int& ra = a;
    // int& b = 10; // 该语句编译时会出错,b为常量
    const int& b = 10;
    double d = 12.34;
    //int& rd = d; // 该语句编译时会出错,类型不同
    const int& rd = d;
}

1.权限的放大

此类是权限的放大,a是不能修改的常量,给a取了别名b同样不能修改,但是取别名时只是给了名字b并没有强调不能修改权限,放大了权限,使用错误。

2.权限的平移

a能做的事c也能做,a不能做的c也不能做。

3.权限的缩小

在初始化x时没有强调权限,x可以随意更改,给x取了别名y,在取别名时强调y不能改变,此类是权限的缩小。(理解为x什么都可以干,y只能吃饭喝水,做事有限制)

4.赋值

赋值是产生一个临时变量,i的值给临时变量,临时变量是double类型,临时变量的值赋给d

临时变量具有常性,不能用其他别名

所以下面的形式错误,是一种权限的放大

正确形式

同理

第一个调用函数,用ret接收时,首先产生一个临时拷贝a的值,临时常量具有常性,再将临时拷贝的值给ret,ret接收值后无论怎么改变不会影响函数里的a

第二个调用函数,同理会产生一个拷贝,拷贝a的值,临时常量具有常性,不能用ret作为常量的别名。

更改为权限平移是正确的

使用场景

1. 做参数  形参的改变会影响实参

void Swap(int& left, int& right)
{
   int temp = left;
   left = right;
   right = temp;
}

2. 做返回值

注意: 如果函数返回时,出了函数作用域, 如果返回对象还在( 还没还给系统 ) ,则可以使用
引用返回,如果已经还给系统了,则必须使用传值返回。
这里以顺序表为例使用引用的便利

1. 使用 cout 标准输出对象 ( 控制台 ) cin 标准输入对象 ( 键盘 ) 时,必须 包含 < iostream > 头文件以及按命名空间使用方法使用std
2. cout cin 是全局的流对象 endl 特殊的 C++ 符号表示换行输出,他们都包含在包<iostream >头文件中。
3. <<是流插入运算符,>>是流提取运算符
4. 使用 C++ 输入输出更方便,不需要像 printf/scanf 输入输出时那样,需要手动控制格式。C++的输入输出可以自动识别变量类型。
int& Add(int a, int b)
{
    int c = a + b;
    return c;
}
int main()
{
    int& ret = Add(1, 2);
    Add(3, 4);
    cout << "Add(1, 2) is :"<< ret <<endl;  输出ret的值
    return 0;
}

ret作为c的别名接收函数的返回值,第一次传入参数c位置的值结果为3,第二次传参c位置的值结果为7,c改变了,函数返回值改变,ret作为c的别名也改变了。所以运行结果是7

传值、传引用效率比较

以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直
接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效
率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。

引用和指针的区别

语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。

底层实现上实际是有空间的,因为引用是按照指针方式来实现的。

引用和指针的不同点:

1. 引用概念上定义一个变量的别名,指针存储一个变量地址。
2. 引用 在定义时 必须初始化 ,指针没有要求
3. 引用 在初始化时引用一个实体后,就 不能再引用其他实体 ,而指针可以在任何时候指向任何
    一个同类型实体
4. 没有 NULL 引用 ,但有 NULL 指针
5. sizeof 中含义不同 引用 结果为 引用类型的大小 ,但 指针 始终是 地址空间所占字节个数 (32
    位平台下占 4 个字节 )
6. 引用自加即引用的实体增加 1 ,指针自加即指针向后偏移一个类型的大小
7. 有多级指针,但是没有多级引用
8. 访问实体方式不同, 指针需要显式解引用,引用编译器自己处理
9. 引用比指针使用起来相对更安全
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值