有关C++引用操作的学习记录

前言

鉴于本人学完就忘的特殊体质,决定把一些有意义的知识进行简单的记录。
在本篇中,重点介绍c++关于引用的相关知识。


引用做函数参数

这里我们综合对比三种函数参数设置方式,分别为:

  • 值传递
  • 地址传递(指针)
  • 引用传递

所用代码如下:

// arrayone.cpp -- small arrays of integers
#include <iostream>

using namespace std;

//值传递
void swap01(int a, int b)
{
    int temp = a;
    a = b;
    b = temp;
}

//地址传递
void swap02(int *a, int *b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}
//引用传递
void swap03(int &a, int &b)
{
    int temp = a;
    a = b;
    b = temp;
}

int main()
{
    int a = 10;
    int b = 20;

    swap01(a, b);
    cout << "swap01" << endl;
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;
    swap02(&a, &b);
    cout << "swap02" << endl;
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;
    swap03(a, b);
    cout << "swap03" << endl;
    cout << "a = " << a << endl;
    cout << "b = " << b << endl;

    system("pause");
    return 0;
}

引用可以理解为,为变量起一个别名,别名和原名指向同一个内存空间,从而对二者的操作完全等价。
典型的引用初始化如下:

int a = 10;
int &b = a;

这样,a与b完全等价。
在代码中,我们使用了交换两个变量的值来观察函数调用效果。
其中,值传递只改变了形参,地址和引用传递均改变了实参,所以在主函数中打印a和b的值,就会出现交换的效果。
对比地址传递和引用传递,引用传递只需要在函数定义时采用对变量加一个&符号构成引用传递,就可以实现和地址传递相同的功能,相比地址传递反复的解引用和复杂的定义,要简便很多。
函数运行效果如下:
在这里插入图片描述


引用做函数返回值

这里主要有两个主要的关注点:

  1. 不要返回局部变量的引用
  2. 函数的调用可以作为左值

废话不多说,直接上代码!

// arrayone.cpp -- small arrays of integers
#include <iostream>

using namespace std;

//引用做函数的返回值
//1.不要返回局部变量的引用
int &test01() //这里是用引用的方式做返回值定义函数
{
    int a = 10; //存放在栈区,不能返回(局部变量)
    return a;   //非法操作
}

//2.函数的调用可以作为左值
int &test02() //这里是用引用的方式做返回值定义函数
{
    static int a = 10; //静态变量,存放在全局区,全局区数据在程序结束后释放
    return a;          //合法操作
}

int main()
{
    int &ref = test02();
    cout << "ref = " << ref << endl;
    cout << "ref = " << ref << endl;

    test02() = 1000; //这里返回了a的引用,相当于就是a,ref是a的别名
    cout << "ref = " << ref << endl;
    cout << "ref = " << ref << endl;
    system("pause");
    return 0;
}

对于第一点,不要返回局部变量做引用值,可以参考子函数test01(),这里的函数定义方式是把引用作为函数返回值,即可用于一个引用(别名)赋给这个返回的变量。
由于这个操作是把一个变量起一个别名,所以原名不能是局部变量,因为它存在于栈区,函数调用结束就被释放掉了,所以test01()中的返回是非法操作。
对于第二点,对于返回引用的函数,函数的调用可以作为左值,观察子函数test02(),其变化之处在于定义的变量是一个静态变量,静态变量存在于程序的全局区,是在程序结束时释放,所以在程序生命周期中一直存在,可以作为函数返回值。
这里我们用一个引用ref作为a的别名。
所谓函数调用可以作为左值,可以这样理解,这里就是静态变量a赋值为1000,证明方式为输出ref(a的别名),可以看出,ref已经变成了1000。
函数运行结果如下:
在这里插入图片描述
另外,a实际上不能拿到子函数之外,例如这样就会报错:

test02() = 1000; //这里返回了a的引用,相当于就是a,ref是a的别名
cout << "a = " << a << endl;//不能这么使用

现在还不清楚函数作为左值具体有什么功能,欢迎小伙伴在评论区留言交流讨论。


引用的本质

对于引用,其本质就是一个指针常量,具体可以参考以下代码:

// arrayone.cpp -- small arrays of integers
#include <iostream>

using namespace std;

//引用的本质
int ref = 0;//自己没事找事看看会出现什么现象
//发现是引用,转换为 int* const ref = &a;
void func(int &ref)
{
    ref = 100; // ref是引用,转换为*ref = 100
}

int main()
{
    cout << "ref = " << ref << endl;

    int a = 10;
    int &ref = a; //自动转换为 int* const ref = &a; 指针常量是指针指向不可改,也说明为什么引用不可更改

    ref = 20; //内部发现ref是引用,自动帮我们转换为: *ref = 20;

    cout << "a = " << a << endl;
    cout << "ref = " << ref << endl;

    func(a);
    
	cout << "a = " << a << endl;
    cout << "ref = " << ref << endl;

    system("pause");
    return 0;
}

简单介绍一下代码:
从主函数定义a开始(先忽略其他的显示),当我们创建ref引用时,编译器将该代码:

int &ref = a;

识别为指针常量的初始化代码:

int * const ref = &a;

所谓指针常量,就是定义了一个指向地址固定,指向地址所在内存的值可以变化的指针,但是由于C++自动识别了引用,所以能够在一定程度上降低代码的输入复杂度(肯定还有别的作用)。
之后凡是用到引用ref时,系统均自动识别为:

ref = 10;//引用的用法
*ref = 10;//编译器识别到的

这样我们就对引用有了更加深入的理解。
对于创建的子函数,本身没有引起我的太大兴趣,仅仅是引用作为函数参数进行传递,但对于程序运行产什么了一些疑问:
如果有一个同名的全局变量,反复定义和使用引用,会有什么效果?
于是笔者创建了一个名为ref的全局变量,具体程序运行结果如下:
在这里插入图片描述
由此可见,在定义ref引用前,程序输出全局变量定义的数据。
在定义ref引用后,似乎覆盖了ref这个全局变量,之后的操作一直是作为引用了。
具体是什么原因有待探讨???


常量引用

引用作为一种“起别名”的方式,如果我们不希望这个别名不能改变原名的数值,应当怎么做呢?
这里就要用到常量引用了。
先说一下定义常量引用的方法,代码如下:

	//int &ref = 10;//非法引用,引用要引向合法的内存空间
    //该行程序相当于:int temp = 10;  const int &ref = temp;
    int const &ref = 10; //没有原名(一般不这么用)

第一行展示了错误的定义方式,因为没有给引用合法的内存空间(找不到内存)。
第三行展示了正确的定义方式,可以看到,它相当于:

	int temp = 10;  
	const int &ref = temp;

不过这个temp并不显示在程序中(不存在),是编译器内部完成的等效动作。
至于常量引用,实际上一般用于函数调用,从而防止子函数修改实参,错误代码如下:

void showValue(const int &temp)
{
    temp = 1000;//不小心修改了这个数据,报错!
    cout << "temp = " << temp << endl;
}

这里,形参设置为了常量引用,所以在子函数中不可以修改其数值,否则会报错。


结语

以上就是关于引用的简单总结,后续会继续补充der!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值