引用从表层来看就是内存单元的别名。从底层来看,和指针处理相同,也开辟内存,在用到引用变量的地方系统会自动解引用。一般初学者很容易把引用和指针混淆一起,但他们并不一样。
int m; //m是被引用物
int &n=m; //n是m的一个引用
n 相当于 m 的别名(绰号),对 n 的任何操作就是对 m 的操作。例如有人名叫王小 毛,他的绰号是“三毛”。说“三毛”怎么怎么的,其实就是对王小毛说三道四。所以 n 既不是 m 的拷贝,也不是指向 m 的指针,其实 n 就是 m 它自己。
引用和指针的区别如下:
(1)引用被创建的同时必须被初始化,指针则可以在任何时候被初始化 。
(2)不能有 NULL 引用,引用必须与合法的存储单元关联,指针则可以是 NULL。
(3)一旦引用被初始化,就不能改变引用的关系,指针则可以随时改变所指的对象 。
int i = 5;
int j = 6;
int &k = i;
k = j; // k 和 i 的值都变成了 6;
(4)指针可以有多级,但是引用只能是一级。
int **p; //合法
int &&a; //不合法的
(5)"sizeof引用"得到的是所指向的变量(对象)的大小,而"sizeof指针"得到的是指针本身的大小。
(6)指针和引用的自增(++)运算意义不一样,对引用的操作直接反应到所指向的对象,而不是改变指向;而对指针的操作,会使指针指向下一个对象,而不是改变所指对象的内容。
#include<iostream>
using namespace std;
int main(int argc,char** argv)
{
int i=10;
int& ref=i;
ref++;
cout<<"i="<<i<<endl; //11
cout<<"ref="<<ref<<endl; //11
int j=20;
ref=j;
ref++;
cout<<"i="<<i<<endl; //21
cout<<"ref="<<ref<<endl; //21
cout<<"j="<<j<<endl; //20
return 0;
}
对ref的++操作是直接反应到所指变量之上,对引用变量ref重新赋值"ref=j",并不会改变ref的指向,它仍然指向的是i,而不是j。理所当然,这时对ref进行++操作不会影响到j。而这些换做是指针的话,情况大不相同。
(7)const对指针和引用的限定是有差别的。
第一点 :常量指针VS常量引用
常量指针:指向常量的指针,在指针定义语句的类型前加const,表示指向的对象是常量。定义指向常量的指针只限制指针的间接访问操作,而不能规定指针指向的值本身的操作规定性。常量指针定义"const int* pointer=&a"告诉编译器,*pointer是常量,不能将*pointer作为左值进行操作。
常量引用:指向常量的引用,在引用定义语句的类型前加const,表示指向的对象是常量。也跟指针一样不能利用引用对指向的变量进行重新赋值操作。
第二点:指针常量VS引用常量
在指针定义语句的指针名前加const,表示指针本身是常量。在定义指针常量时必须初始化!而这是引用天生具来的属性,不用再引用指针定义语句的引用名前加const。
指针常量定义"int* const pointer=&b"告诉编译器,pointer是常量,不能作为左值进行操作,但是允许修改间接访问值,即*pointer可以修改。
第三点:常量指针常量VS常量引用常量
常量指针常量:指向常量的指针常量,可以定义一个指向常量的指针常量,它必须在定义时初始化。常量指针常量定义"const int* const pointer=&c"告诉编译器,pointer和*pointer都是常量,他们都不能作为左值进行操作。
而就不存在所谓的"常量引用常量",因为跟上面讲的一样引用变量就是引用常量。C++不区分变量的const引用和const变量的引用。程序决不能给引用本身重新赋值,使他指向另一个变量,因此引用总是const的。如果对引用应用关键字const,起作用就是使其目标称为const变量。即没有:Const double const& a=1;只有const double& a=1;
引用的主要功能是传递函数的参数和返回值。
C++语言中,函数的参数和返回值的传递方式有三种:值传递、 指针传递和引用传递。
(1)“值传递”:
# include<iostream>
using namespace std;
void Func1(int x)
{
x=x+10;
}
int main()
{
int n=0;
Func1(n);
cout<<"n="<<n<<endl; //n=0
return 0;
}
由于 Func1 函数体内的 x 是外部变量 n 的一份拷贝, 改变 x 的值不会影响 n, 所以 n 的值仍然是 0。
(2)“指针传递”:
# include<iostream>
using namespace std;
void Func2(int *x)
{
(*x)=(*x)+10;
}
int main()
{
int n=0;
Func2(&n);
cout<<"n="<<n<<endl; //n=10
return 0;
}
由于 Func2 函数体内的 x 是指向外部变量 n 的指 针,改变该指针的内容将导致 n 的值改变,所以 n 的值成为 10。
(3)"引用传递“:
# include<iostream>
using namespace std;
void Func3(int &x)
{
x=x+10;
}
int main()
{
int n=0;
Func2(n);
cout<<"n="<<n<<endl; //n=10
return 0;
}
由于 Func3 函数体内的 x 是外部变量 n 的引用,x 和 n 是同一个东西,改变 x 等于改变 n,所以 n 的值成为 10。
对比上述三个示例程序,会发现“引用传递”的性质象“指针传递”,而书写方式像“值传递”。实际上“引用”可以做的任何事情“指针”也都能够做,为什么还要“引用” 这东西? 答案是“用适当的工具做恰如其分的工作” 。 指针能够毫无约束地操作内存中的如何东西,尽管指针功能强大,但是非常危险。 就像一把刀,它可以用来砍树、裁纸、修指甲、理发等等,谁敢这样用? 如果的确只需要借用一下某个对象的“别名”,那么就用“引用”,而不要用“指针”, 以免发生意外。比如说,某人需要一份证明,本来在文件上盖上公章的印子就行了,如 果把取公章的钥匙交给他,那么他就获得了不该有的权利。