目录:
-
引用的定义
-
引用的应用
-
引用的提高
-
常引用
-
引用的本质
1.引用的定义
先来说说何为引用,及就是引用的定义。我看到的一些书上给出的定义是:变量名,本身是一段内存的引用,
即别名(alias)。此处引入的引用,是为己有变量起一个别名。下面是代码定义:
int a; int &ra = a;
-
其中变量ra是int型变量的引用,是对int型变量a的声明,引用的变量不能独立存在,必须初始化,并且与原类型保持一致,且不分配内存空间。
- 声明关系,一经声明,不可再次被更改。
- 可以对引用类型的变量,再次进行引用。多次引用的结果就是,某一变量具有多个别名,多个别名之间的关系是相互平行的关系,不像指针一样有一级指针,二级指针等。
- 引用不是一种独立的数据类型。对引用只有声明,没有定义。
- 辨别引用于其他, “&” 前有数据类型时,是引用,例如:int & ra; double & b; 等。其他则是取地址符,或按位与。
2.引用的应用
引用的目的就是取代指针传参。C++引入引用后,只要是可以用引用来解决的问题,都避免使用指针。引用的使用可以简单的分为以下几种:
- 单独对变量进行引用
- 作为函数的参数
3.引用的提高
引用的本质就是指针,不过是加了const的指针。C++对指针做了包装,使得引用有指针的良好性质。以下是在使用引用是需要注意的几点:
- 可以对指针进行引用,但不能定义引用的指针
int a = 10;
int *p = &a;
int *& rp = p;//对int型指针变量p起别名rp。
int &* prp = &rp; //错误,指向引用的指针非法
2.指针有一级指针、二级指针等,但引用无二级引用
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
int *p;
int * * ptp= &p;
//可以为引用再次声明引用,但不可建立引用的引用。避免了指针调计的"失误"
int a;
int & ra = a;
int & rb = a;
int & rc = rb;//引用可以被再次声明的引用所引用。
int && rrc = rc; //引用的引用,是不存在的。
return 0;
}
3.数组中可以全部存放为地址(及就是指针数组),但是不可存放引用
4.常引用
在C++中const 定义的变量称为常变量。以变量的形式,常量的作用,用作常量。常用来替代#define 宏常量。
常引用的一些特性:
1.接收函数返回值
2.接收表达式的值
3.接收不同类型的变量
5.引用的本质
之前介绍过,引用在声明的时候不分配空间。那么我们怎样才能证实在C++编译器中到底有没有给引用变量分配内存空间呢?
首先会这么想:
#include "iostream" using namespace std; void foo(int& ra, char& rb) { cout << sizeof(ra) << " " << sizeof(rb) << endl; } int main(int argc, char const* argv[]) { int a; char b; foo(a, b); return 0; }
但仔细想想,如果这么做的话,那岂不是在计算引用的大小的时候就调用函数了,则在调用函数的时候,就开始给形参分配变量了,所以,这样并不能证实C++编译器有没有给引用变量分配内存空间。既然这样,那我们可以试着把引用变量单独列出来,使其不和具体的对象发生关系,如下所示:
#include "iostream" using namespace std; struct TypeP { char* p; }; struct TypeC { char c; }; struct TypeR { char& r; }; int main(int argc, char const* argv[]) { cout << "sizeof(TypeP):" << sizeof(TypeP) << " sizeof(TypeC)" << sizeof(TypeC) << " sizeof(TypeR)" << sizeof(TypeR) << endl; return 0; }
这样以来,就可以初步断定引用是经过包装后的指针。但是,引用在使用的时候必须要初始化,在之前的学习过程中,const的常量在声明变量的时候需要初始化。那这样一来,引用则就是const声明的指针变量。也就是说:int &p;等同于int * const p;