C++中的引用和inline 和 nullptr全面解析

 更新时间:2026年05月11日 10:16:50   作者:.道阻且长.  
文章主要介绍C++中引用的概念、特性及使用方法,包括引用的定义、初始化、作用域、const引用等,并与指针进行了对比,此外,还介绍了内联函数和nullptr的关键知识点,感兴趣的朋友一起看看吧

一.引用

1.1引用的概念与定义

引⽤不是新定义⼀个变量,⽽是给已存在变量取了⼀个别名,编译器不会为引⽤变量开辟内存空间, 它和它引⽤的变量共⽤同⼀块内存空间。⽐如:⽔壶传中李逵,宋江叫"铁⽜",江湖上⼈称"⿊旋 ⻛";林冲,外号豹⼦头;

类型& 引⽤别名=引⽤对象

C++中为了避免引⼊太多的运算符,会复⽤C语⾔的⼀些符号,⽐如前⾯的>,这⾥引⽤也和取 地址使⽤了同⼀个符号&,⼤家注意使⽤⽅法⻆度区分就可以。(吐槽⼀下,这个问题其实挺坑的,个 ⼈觉得⽤更多符号反⽽更好,不容易混淆

从这里我们可以看出,i和j的地址是一样的,说明他们指向同一块空间,引用不会开辟新空间

1.2 引⽤的特性

1.引⽤在定义时必须初始化

2.⼀个变量可以有多个引⽤

3. 引⽤⼀旦引⽤⼀个实体,再不能引⽤其他实体

这里我们可以看出,引用b指向了a,说明是给a取了别名;若要让b在指向d,d现在是20,这里就是赋值的意思,将20赋值给b,而b又是a的别名,所以a的值也发生了改变

4.别名++,其存在的变量也++

1.3 引⽤的使⽤

1.3.1引用传参的使用

1. 引⽤在实践中主要是于引⽤传参和引⽤做返回值中减少拷⻉提⾼效率和改变引⽤对象时同时改变被引⽤对象。

2.引⽤传参跟指针传参功能是类似的,引⽤传参相对更⽅便⼀些。

如果使用指针来实现两个数的交换,首先Swap1中的ab需要开辟一个空间来指向x1,y1的地址,需要拷贝;

若用引用的话,只是给x2,y2起别名,ab发生改变,x2,y2也同时发生改变,但这种情况不会开辟新空间,不需要拷贝优于指针

上面的图返回的是临时变量,是一个值,需要存储起来,不能直接进行修改;

下面的图返回的是它的引用,可以进行直接修改

3.引⽤返回值的场景相对⽐较复杂,我们在这⾥简单讲了⼀下场景,还有⼀些内容后续类和对象章节 中会继续深⼊讲解。

4.引⽤和指针在实践中相辅相成,功能有重叠性,但是各有特点,互相不可替代。C++的引⽤跟其他 语⾔的引⽤(如Java)是有很⼤的区别的,除了⽤法,最⼤的点,C++引⽤定义后不能改变指向, Java的引⽤可以改变指向。

5.⼀些主要⽤C代码实现版本数据结构教材中,使⽤C++引⽤替代指针传参,⽬的是简化程序,避开 复杂的指针,但是很多同学没学过引⽤,导致⼀头雾⽔。

1.3.2传引用返回

再说传引用返回,这里返回的是ret的别名

但是这样的传引用返回的行为,本质上是非常危险的,func函数结束之后,func栈帧就销毁了,但是tmp依旧是ret这块空间的别名,tmp依旧在访问ret,就相当于野指针的访问。此时返回的就不一定是0了,也有可能是随机值

正确传引用返回:

如图出了作用域,func1结束,ret还在,此时被static修饰的ret就不存在func1的栈帧之中了

1.4 const引用


1.可以引用一个const对象,但是必须用const引用。const引用也可以引用普通对象,因为对象的访问权限在引用过程中可以缩小,但是不能放大。

   如图,如果a被const修饰了,引用就不能使用了,此时a不能改变,但是b是a的别名,可以改变a,这就是一个权限放大的场景,权限是不能放大的,想要正常引用就要权限移b也要被const修饰

用const修饰a,a只能读不能写;而b是a的引用,没有用const,那么b既能读又能写,放大了a的权限

这样写才是正确的,a和b都只能读不能写。

a可读可写,但是引用后只能读不能写,这样是正确的,缩小了权限

2.不需要注意的是类似 int& rb = a*3; double d = 12.34; int& rd = d; 这样⼀些场 景下a*3的和结果保存在⼀个临时对象中, int& rd = d 也是类似,在类型转换中会产⽣临时对 象存储中间值,也就是说,rb和rd引⽤的都是临时对象,⽽C++规定临时对象具有常性,所以这⾥ 就触发了权限放⼤,必须要⽤常引⽤才可以。

  • int&非常量左值引用,它只能绑定到一个可修改的左值(即有内存地址的变量)。
  • a * 3 是一个临时右值(计算结果是一个没有名字的临时值,没有持久的内存地址),无法被非常量左值引用绑定。

正确写法是在引用前面加上const修饰,只能读。

  • double d = 12.34;定义了一个 double 类型变量 d,值为 12.34
  • int i = d;
    • double 类型的 d 隐式转换为 int,截断小数部分,i 的值为 12
    • 这是直接赋值,i 是一个独立的新变量,和 d 共享内存。
  • const int& ri = d;
    • 试图将 double 类型的 d 绑定到 const int& 类型的引用。
    • 由于类型不匹配,编译器会生成一个临时的 int 类型对象,将 d 截断为 12 存入该临时对象,然后让 ri 绑定到这个临时对象。
    • 这就是图中标注的「临时对象」:它是一个匿名的、生命周期被 const int& 延长的临时变量,ri 并不直接引用 d,而是引用这个临时对象。

1.5指针与引用的关系

对比维度引用(Reference)指针(Pointer)
本质概念变量的别名,不单独占用内存空间存储变量的内存地址,需要占用内存空间
初始化要求定义时必须初始化,且必须绑定到一个已存在的对象建议初始化,但语法上不强制,可以先声明后赋值
指向关系初始化后无法再更改绑定对象,始终指向最初绑定的变量可以随时改变指向,指向不同的变量或空地址
访问方式直接使用引用名访问目标对象,无需解引用需要通过 * 解引用操作符才能访问目标对象
sizeof 含义sizeof(引用) 结果为所引用类型的大小(如 sizeof(int&) = 4)sizeof(指针) 结果为地址空间的字节数(32 位平台为 4 字节,64 位平台为 8 字节)
安全性不存在空引用、野引用问题,使用相对更安全容易出现空指针、野指针问题,使用时需额外判断合法性
典型用途函数参数传递(避免拷贝)、函数返回值(保证非空)动态内存管理、数组遍历、复杂数据结构(链表 / 树)的节点操作

二、inline

先看一下宏常见的问题

看似没有问题,但这个宏在另一种场景下就又不对了

所以可以看出宏函数很容易出现问题,很复杂,还不能调试

所以C++之父就搞了个内联出来

写个函数是不容易写错的,但写个宏函数很容易写错
宏函数的优点就是可以提高效率,适用于高频调用的小函数,预处理阶段宏会替换,不建立栈帧,而且宏甚至可以传类型

C++中内联就是用来替换宏的

用inline修饰的函数叫做内联函数,编译时C++编译器会在调用的时候展开(不是把函数部分的代码直接放到主函数处,而是把函数地方的逻辑经过一定的处理,经过编译器自己分析,用于主函数处)内联函数,这样调用内联函数就不需要建立栈帧了,就可以提高效率
inline对于编译器而言只是一个建议,也就是说,你加了inline编译器也可以选择在调用的地方不展开,不同编译器关于inline什么情况展开各不相同,因为C++标准没有规定这个。inline适用于频繁调用的短小函数,对于递归函数,代码相对多一些的函数,加上inline也会被编译器忽略。

三、nullptr

nullptr是C++11的一个关键字,是用来替代C语言的NULL的

NULL实际上是一个宏,在传统的C头文件(stddef.h)中,可以看到如下代码:

#ifndef NULL
    #ifdef __cplusplus
        //C++中的NULL被替换为0,默认为整型
        #define NULL    0
    #else
        //C语言中的NULL也被替换为0,但是被强制类型转换为(void*)
        #define NULL    ((void *)0)
    #endif
#endif

C++中NULL可能被定义为字面常量0,或者C中被定义为无类型指针(void * )的常量。不论采取何种定义,在使用空值的指针时,都不可避免的会遇到一些麻烦,本想通过f(NULL)调用指针版本的f(int * )函数,但是由于NULL被定义成0,调用了f(int x),因此与程序的初衷相悖。f((void* )NULL);调用会报错

在C++之中,void* 给int* 是需要强制类型转换的
C++11中引用nullptr,nullptr是一个特殊的关键字(就相当于语法层在编译的时候就特殊解决该问题了),nullptr是一种特殊类型的字面量,它可以转换成任意其它类型的指针类型(值还为0)。使用nullptr定义空指针可以避免类型转换的问题,因为nullptr只能被隐式转换为指针类型,而不能被转换为整数类型。

到此这篇关于C++中的引用和inline 和 nullptr全面解析的文章就介绍到这了,更多相关C++引用和inline 和 nullptr内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++中utf8字符串和gbk字符串的转换方法

    C++中utf8字符串和gbk字符串的转换方法

    文章介绍了C++中UTF-8字符串和GBK字符串之间的转换,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧
    2025-02-02
  • C++实现冒泡排序的多种方式详解

    C++实现冒泡排序的多种方式详解

    冒泡排序是最基础的排序算法之一,它的核心思想是通过相邻元素的比较和交换,将较大的元素逐步冒泡到数组的末尾,今天我们来分析三种不同的冒泡排序实现方式,每种都有其独特之处,需要的朋友可以参考下
    2025-10-10
  • C++堆排序算法实例详解

    C++堆排序算法实例详解

    这篇文章主要介绍了C++堆排序算法,简单分析了堆排序算法的原理并结合实例形式分析了C++实现堆排序的具体操作技巧,需要的朋友可以参考下
    2017-08-08
  • Clion2020.2.x最新激活码破解版附安装教程(Mac Linux Windows)

    Clion2020.2.x最新激活码破解版附安装教程(Mac Linux Windows)

    Clion2020增加了很多新特性,修复了大量bug,大大提高了开发效率。这篇文章主要介绍了Clion2020.2.x最新激活码破解版附安装教程(Mac Linux Windows),需要的朋友可以参考下
    2020-11-11
  • C++的头文件和实现文件详解

    C++的头文件和实现文件详解

    这篇文章主要介绍了C++的头文件和实现文件详解的相关资料,需要的朋友可以参考下
    2015-01-01
  • c语言在控制台判定鼠标左键的小例子

    c语言在控制台判定鼠标左键的小例子

    c语言在控制台判定鼠标左键的小例子,需要的朋友可以参考一下
    2013-06-06
  • C语言实现静态链表

    C语言实现静态链表

    这篇文章主要为大家详细介绍了C语言实现静态链表,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-07-07
  • Dev-C++无法使用bits/stdc++.h问题及解决

    Dev-C++无法使用bits/stdc++.h问题及解决

    这篇文章主要介绍了Dev-C++无法使用bits/stdc++.h问题及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • C语言指针笔试题全面解析

    C语言指针笔试题全面解析

    这篇文章主要介绍了C语言指针笔试题全面解析,介绍了其相关概念,然后分享了几种用法,具有一定参考价值。需要的朋友可以了解下。
    2021-09-09
  • 用贪心法求解背包问题的解决方法

    用贪心法求解背包问题的解决方法

    本篇文章是对用贪心法求解背包问题的解决方法进行了详细的分析介绍,需要的朋友参考下
    2013-05-05

最新评论