
文章目录
- 一、引用
-
-
- 引用的概念
-
- 引用的特点
-
- 引用的使用
-
- const引用
-
- 引用和指针
-
- 二、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只能隐式地转换为指针类型,不能转换为整数类型。


本篇完,感谢阅读