C++语言进阶 – 引用变量

前言

看了网上的一些文章,我想大家在学习引用的时候总是容易把引用理解为变量的别名,这其实是错误的。引用实际上是给一个对象起别名,相当于给一个同类型的对象起别名,更严谨的来说上应该是相当于给对象/变量所在的内存空间起别名。

基本概念

C++中可以定义“引用”。定义方式如下:

语法:数据类型 &别名 = 同类型的某对象或变量名

作用:定义了一个某种类型的引用,并将其初始化为引用某个同类型的对象。相当于给一个同类型的对象起别名,更严谨的来说上应该是相当于给对象/变量所在的内存空间起别名。

代码:

#include "stdlib.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
    int a=10;
    int &b=a;
    cout <<"Loc(a):"<<&a<<endl;
    cout <<"Loc(b):"<<&b<<endl;
    system("pause");
    return 0;
}

输出:

Loc(a):0x61fe14
Loc(b):0x61fe14
请按任意键继续. . .

注意:网上很多人认为,被引用的只能是变量,这种说法,笔者认为是不严谨的。看下面这种情况:

    int *p=new int(2);
    int &c=*p;
    cout <<"Loc(c):"<<&c<<endl;
    cout <<"c:"<<c<<endl;
    c=11;
    cout <<"p:"<<*p<<endl;
    *p=12;
    cout <<"c:"<<c<<endl;
    cout <<"p:"<<*p<<endl;

为引用变量初始化的右值*p是变量吗?显然不是吧,这段代码是可以正常输出的。结果如下:

Loc(c):0x24d2430
c:2
p:11
c:12
p:12

这样或许还是不太明显,那么来看看这个:

int &c=new int(2);

右值替换为 new int(2) ,得到的结果依然是正确的。

最终我们可以得出引用变量是定义了一个某种类型的引用,并将其初始化为引用某个同类型的对象。

引用特性

  1. 定义引用时,只能使用同类型对象去初始化引用
    引用相当于为一个变量“取别名”,也就要求了被引用的必须为一个同类型的对象。
  2. 一旦初始化后,引用了一个对象将无法引用其他对象。
    定义引用时初始值会与引用进行绑定,故引用一旦引用一个对象将无法引用其他对象,因为对引用的赋值实际上是对被引用对象的赋值,通过下面代码可证明:
        int a=10;
        int &b=a;
        int p=2;
        int &c=p;
        c=a;
        cout<<c<<endl;
        cout<<p<<endl;

    输出结果:

    10
    10
  3. 一个变量可有多个引用

引用变量占空间吗

这里先问大家一个问题:我们知道值类型的变量是不占内存的,那么引用变量它占内存吗?

网上的答案众说纷纭,笔者查阅了一些有详细论证的文章,可以先告诉大家一个结论:引用变量它是占内存空间,所占内存空间就是引用所引用的对象的地址,故占用的内存空间的大小和指针类型的大小是相同的,在32位系统中会占4个字节。

通过几篇文章中给出的反汇编代码,我们可以发现在引用变量初始化那段代码会出现两行汇编代码

lea eax,[var]
move dword ptr [refVar],eax

笔者对这两段汇编代码的大概理解: 检查var变量是否在寄存器中,再把寄存器中的var的地址赋给以refVar为地址的一块内存区域。从上面汇编代码可以看出,这两行汇编代码跟指针的汇编代码是完全一致的,虽然引用是一个对象的别名,但是在汇编层面,和指针是一样的。

 

参考文章:C++的那些事:你真的了解引用吗

2022/11/8 0:25


2022/11/8 :21:10

引用的本质

前面通过汇编语言我们了解到,引用在C++内部实现是一个指针。

为了进一步证明,我百度查了一下关键字“引用的本质是什么?”。结果真的令我张目结舌,看看吧。

C++语言进阶 &#8211; 引用变量

有说常量指针的,有说指针常量的。我真的会谢!我已经数不清几次吐槽现在的互联网文章了,一个错的..一堆引用 复制粘贴..。

首先说明这两个概念是完全不一样的,今天就以我对引用的理解,把这个概念跟大家说清楚吧。

我们知道引用变量一旦引用一个对象将无法引用其他对象,因为对引用的赋值实际上是对被引用对象的赋值。那这个不就是很明显吗?

笔者之前写过指针的文章,分别介绍过了常量指针与指针常量,这里再介绍一下。

  • const修饰指针 --- 常量指针
    const修饰*p 表示通过指针所指的值是常量,指针的指向可以修改,指针指向的值不可修改
  • const修饰常量 --- 指针常量
    const修饰p,表示指针是常量,指针的指向不可以改,通过指针指向的值可以改。

那引用变量概念不就很明显跟指针常量概念一样吗?为什么网上能说成常量指针?麻烦各位CSDN大佬们,在你们撰写专业名词、概念相关的内容能好好认真的查阅一下吗?

关于 常量指针与指针常量 详细证明过程见文章 C++语言入门-指针 - 麦瑞克博客 (unitymake.com)

编译器内部操作

int &ref=a;
ref=20;

当C++内部发现ref:引用变量 是引用类型时,会自动帮我们进行解引用的操作  *ref=20;

引用变量作形参

示例-交换值:

void SwapNumByReference(int &a,int &b)
{
    int temp=a;
    a=b;
    b=temp;
}

引用形参与指针形参类似,我觉得应该没什么需要特别指出,就不赘述了,对这块不清楚的可以先去看下我之前那几篇指针的文章:

C++基础入门 - 值传递与引用参数|指针与函数 - 麦瑞克博客 (unitymake.com)

指针专辑 - 麦瑞克博客 (unitymake.com)

引用变量作返回值

与指针当返回值类似,引用变量作返回值也有以下规则。详细证明见指针 C++语言入门-指针

注意:

  • 不要返回局部变量的引用;
  • C++支持函数调用返回作为左值作赋值操作;

引用变量作常量

作用:防止引用变量所引用的值被修改,主要用来修饰形参。

C++语言进阶 &#8211; 引用变量

禁止引用形参修改值:

C++语言进阶 &#8211; 引用变量

代码下载

本文所有案例代码文件:

C++语言进阶 &#8211; 引用变量
来源:诚通网盘 | 提取码:unitymake

2022/11/9 0:23


 

给TA打赏
共{{data.count}}人
人已打赏
开发数据库电脑运维

华为交换机配置端口实例

2023-9-15 14:59:40

开发

解决VSCode编译C++报错No such file or directory问题

2023-9-15 15:22:55

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索