【落羽的落羽 C++】C++入门基础:引用,内联,nullptr

文章目录

  • 一、引用
      1. 引用的概念
      1. 引用的特点
      1. 引用的使用
      1. const引用
      1. 引用和指针
  • 二、inline内联
  • 三、nullptr

一、引用

1. 引用的概念

引用是C++中的一个较为重要的概念。它是给已存在变量取的"别名",编译器不会为引用变量开辟内存空间,它和它引用的变量共用一块内存空间 。比如,"萨姆"是流萤的别名,"萨姆"就是对流萤的引用,当我们称呼萨姆时,指的仍然是流萤这个人。

具体用法是:类型& 引用别名 = 引用对象;

cpp 复制代码
int a = 1;
//b和c是对a的引用,b和c都是a的别名
int& b = a;
int& c = a;
//也可以再对b取别名d,d还是对a的引用,也是他的别名
int& d = b;

可以看到:

b,c,d的值与地址和a是完全相同的:

2. 引用的特点

使用引用时,我们需要注意:

  • 引用在定义时必须初始化
  • 一个变量可以有多个引用
  • 引用变量只能引用定义时指定的对象,无法修改引用对象
  • 因为它们共用一块地址,所以对引用变量的修改也会改变引用对象。
cpp 复制代码
int a = 1;

//没有初始化,会报错:
int& b;

//一个变量可以有多个引用:
int& b = a;
int& c = a;
//后续无法再修改b和c的引用对象了

//对引用变量的修改会改变引用对象:
b = 2; //a,b,c的值变成了2
int d = 3;
c = d; //这里并非是引用,而是赋值。a,b,c的值变成了3

3. 引用的使用

引用在实践中主要用于引用传参和引用做返回值。

引用传参,例如void Swap(int& x, int& y);,函数的形参是引用类型。在调用函数时,x和y分别是对实参的引用,在函数内部交换了x和y的值,也就改变了实参的值。显然,引用传参和传址调用一样,规避了传值调用中无法改名实参的缺点。引用传参和指针传参在功能上是类似的,引用传参相对更方便一点。

引用做返回值的使用涉及到类和对象的概念。简单概括,用普通类型做返回类型,返回值就只是一个常量数值,后续不能再对这个数值进行修改;用引用类型做返回类型,返回值就是函数内return的变量的引用,后续还可以对这个变量进行修改。以后我们再深入理解。

4. const引用

一个const变量也可以引用,但必须用const引用(常引用)const引用也可以引用普通变量,但普通引用不能引用const变量。

当然,被const修饰了,const引用类型自然也不能被修改:

需要注意的是,类似a*2,20这种具有常性的对象,也必须要用常引用:

5. 引用和指针

C++中指针和引用很相似,在实践中它们相辅相成,功能有重叠,但是各有特点,不能互相替代。

  • 引用是给一个变量起别名,不额外开辟空间。指针是存储一个变量的地址,要开空间。
  • 引用在定义时必须要初始化。指针建议初始化,但在语法上不是必须的。
  • 引用在初始化时引用一个对象后,就不能再改变引用对象。而指针可以不断改变指向对象。
  • 引用可以直接访问引用对象。指针需要解引用才能访问指向对象。
  • 引用变量的大小取决于引用类型。指针变量大小始终是4或8个字节。
  • 指针很容易出现空指针和野指针的问题。引用使用起来更安全一点。

二、inline内联

inline是C++中的一个关键字,用来修饰函数。用inline修饰的函数叫做内联函数,编译时C++编译器会在调用函数的地方展开内联函数,这样调用函数时就需要建立栈帧了,可以提高效率。

但inline对于编译器而言只是一个建议,加了inline编译器也可以选择不展开函数,C++没有明确规定展不展开。inline适用于频繁调用的短小函数,对于递归函数或代码相对多一些的函数,加上inline也会被忽略。

当然,C语言中的宏函数也会在预处理时替换展开,但是宏函数在实现中很复杂容易出错,且不容易调试。C++设计出inline的目的就是替代C语言的宏函数。

VS编译器debug版本下是默认不展开inline的,这样方便调试,debug版本想要inline展开需要额外设置。

最后,inline不建议声明和定义分离到两个文件,这样会导致链接错误。因为inline被展开,函数地址没有了,链接时会出现报错。

cpp 复制代码
#define Add(x, y) ((x)+(y)) //宏函数

inline int Add(int x, int y) //内联函数
{
    return x + y;
}

换言之,内联函数像宏函数一样直接在函数调用处展开。它继承了宏函数的优点,但没有宏函数的缺点。

三、nullptr

我们对空指针NULL已经不陌生了。NULL实际上是一个宏,在传统的C头文件stddef.h中,可以找到:

C语言中,NULL被定义成无类型指针(void*)的常量。在C++中,NULL被定义成字面常量0,不论采用哪种定义,在使用NULL时,都可能会遇到问题,比如:

cpp 复制代码
void Fun(int* ptr);
void Fun(int x);

这两个函数构成了函数重载,编译时没有问题。

假如后续调用中有Fun(NULL);,我们本想调用参数是int*的Fun函数,但由于NULL被定义成0,会调用成参数是int的Fun函数;写成Fun((void*)NULL),调用会报错;写成Fun((int*)NULL);才能调用第一个Fun函数:

所以,为了解决这个问题,C++11中引入了nullptr。nullptr是一个关键字,它是一种特殊类型的字面量,可以转换成任意其他类型的指针类型。使用nullptr定义空指针可以避免类型转换的问题,因为nullptr只能隐式地转换为指针类型,不能转换为整数类型。

本篇完,感谢阅读

相关推荐
Mr.NickJJ25 分钟前
JavaScript系列06-深入理解 JavaScript 事件系统:从原生事件到 React 合成事件
开发语言·javascript·react.js
Dream it possible!32 分钟前
LeetCode 热题 100_字符串解码(71_394_中等_C++)(栈)
c++·算法·leetcode
Archer1941 小时前
C语言——链表
c语言·开发语言·链表
My Li.1 小时前
c++的介绍
开发语言·c++
功德+n2 小时前
Maven 使用指南:基础 + 进阶 + 高级用法
java·开发语言·maven
达斯维达的大眼睛2 小时前
qt小项目,简单的音乐播放器
开发语言·qt
面会菜.2 小时前
C语言(队列)
c语言·开发语言
香精煎鱼香翅捞饭2 小时前
java通用自研接口限流组件
java·开发语言
-凌凌漆-2 小时前
【C#】async与await介绍
开发语言·c#
小猿_003 小时前
C语言单链表头插法
c语言·开发语言