先看下面代码:
int dogs = 5;
int* dogsPtr = &dogs;
很明显,指针dogsPtr与dogs“绑定”了,我们可以用*dogsPtr来修改dogs的值。
再看看下面的代码:
int cats = 5;
int& catsRef = cats;
同样的明显,引用catsRef与cats也“绑定”了,我们可以直接用catsRef来修改cats的值。这样看来,引用和指针有着相同的效果,都可以用他们来修改他们指向对象的值。但是,我们可以用下面的语句来看看他们的一些区别:
cout << &dogs << endl;
cout << &dogsPtr << endl;
cout << &cats << endl;
cout << &catsRef << endl;
可以看到,上面两句输出的是不同的地址,而后面两句输出了相同的地址。这就说明了指针是一个变量,占有自己的内存空间,而引用仅仅是某个变量的一个别名,所以它与它引用的变量共享一个内存空间。这样的区别决定了指针可以再赋值,而引用不能。考虑以下代码:
int dogs = 5;
int* dogsPtr = &dogs;
int cats = 6;
dogsPtr = &cats;
这是没有问题的,指针首先指向了dogs然后指向了cats,由于指针自己是一个变量,它先后指向不同的变量,对于它指向的那两个变量是没有影响的。就是说,dogs还是等于5,cats还是等于6。再考虑以下代码:
int dogs = 5;
int& dogsRef = dogs;
int cats = 6;
dogsRef = cats;
这就出问题了,dogs的引用并没有像预想中那样改变为cats的引用,反而修改了dogs的值,正是因为dogsRef是dogs的别名而已,他们两个是真正绑定在一起的,“dogsRef = cats;”就相当于“dogs = cats;”。所以dogs被重新赋值了。
这样看来,引用更像是一个常量指针。
稍微总结一下:
1. 指针可以在任何地方初始化,而引用则必须在声明的时候初始化。
2. 指针可以什么都不指向,而引用必须与某个名称关联,这与他们在内存中的地位决定的。
3. 指针可以改变指向,但引用不能改变引用对象。
小注意:
当且仅当函数参数为const引用,并且实参与引用参数类型不匹配时,C++才会生成临时变量。考虑一下程序,这是一个交换两个数的小程序:
void swap(int &a, int &b) {
int temp;
temp = a;
a = b;
b = temp;
}
设想一下如果没有该限制,当传入两个long型的实参时,由于类型不匹配,会生成两个临时的int型变量以强制转换类型,这样出了swap函数体以后就会被销毁,所以这样就没有达到交换两个数的目的。正因为如此,只有参数为const引用并且传入实参与类型不匹配的时候,才会产生临时变量。