引用和指针都是一种间接访问对象的方式,但是它们有很多不同点:
-
初始化:一个指针可以在声明时或者之后被初始化,也可以被赋值为NULL。例如:
int a = 10;
int *p = &a; // 声明并初始化一个指向a的指针
int *q; // 声明一个指针,未初始化
q = &a; // 初始化指针q为指向a
int *r = NULL; // 声明并初始化一个空指针
而一个引用必须在声明时就被初始化,并且绑定到一个已存在的对象上,不能被赋值为NULL,例如:
int a = 10;
int &r = a; // 声明并初始化一个引用a的别名
int &s; // 错误,引用必须被初始化
int &t = NULL; // 错误,引用不能绑定到NULL
-
重赋值:一个指针可以被重赋值,指向不同的对象,例如:
int a = 10;
int b = 20;
int *p = &a; // 指向a
p = &b; // 指向b
而一个引用不能被重赋值,它一旦绑定到一个对象上,就不能再绑定到其他对象上,例如:
int a = 10;
int b = 20;
int &r = a; // 绑定到a
r = b; // 这不是重赋值,而是把b的值赋给a,相当于a = b;
-
身份:一个指针有自己的内存地址和大小,可以用&和sizeof运算符来获取,例如:
int a = 10;
int *p = &a;
cout << p << endl; // 打印p的值,也就是a的地址
cout << &p << endl; // 打印p的地址
cout << sizeof(p) << endl; // 打印p的大小
#include <iostream>
using namespace std;
void Test() {
int a = 10;
int *p = &a;
cout << *p << endl; // print the value of a
cout << p << endl; // 打印p的值,也就是a的地址
cout << &p << endl; // 打印p的地址
cout << sizeof(p) << endl; // 打印p的大小
}
int main() { // not without main() !!!
Test();
return 0;
}
// 10
// 0x7fffea5d5eec
// 0x7fffea5d5ef0
// 8
而一个引用没有自己的内存地址和大小,它只是原来对象的别名,使用&和sizeof运算符会返回原来对象的地址和大小,例如:
int a = 10;
int &r = a;
cout << r << endl; // 打印r的值,也就是a的值
cout << &r << endl; // 打印r的地址,也就是a的地址
cout << sizeof(r) << endl; // 打印r的大小,也就是a的大小
-
间接层次:你可以有多层嵌套的指针,提供额外的间接访问层次,例如:
int a = 10;
int *p = &a; // 指向a
int **q = &p; // 指向p
cout << **q << endl; // 通过两次解引用访问a的值
而一个引用只能提供一层间接访问层次,例如:
int a = 10;
int &r = a; // 引用a
cout << r << endl; // 通过一次解引用访问a的值