要点:
1. 任何引用必须和存储单元联系。访问引用时,就是访问那个存储单元。
2. 使用引用的规则:
2.1、当引用被创建时,它必须被初始化(指针不用)
2.2、一旦一个引用被初始化为指向一个对象,那么它就不能被改变为指向另一个对象。(指针可以)
2.3、不可能存在NULL的引用。指针有。
3. 函数中的引用:
首先我们看下面例子:
int* f(int* x) { (*x)++; return x; // safe } int& f(int& x) { x++; return x;// safe } int& h() { int q; return q;//error static int x; return x;// OK x lives outside this scope } int main() { int a = 0; f(&a);//Ugly but explicit g(a);// Clean but hidden }
对函数f()的调用缺乏使用引用的方便性和清晰性,但很清楚这是传递一个地址,在函数g()的调用中,地址通过引用被传递,但表面看不出来。
4、常量引用
看下面例子:
void f(int&); void g(const int&); int main() { f(1);//error g(1);//OK return 0; }
f(1)//error的原因:
编译器为一个int类型分派存储单元,同时将其初始化为1,并为其产生一个地址和引用捆绑在一起。对于所有的临时对象,必须同样假设它们不可存取。当改变这种数据的时候,编译器会指出错误。
5、指针引用
在C语言中,如果想改变指针本身而不是它所指向的内容,函数声明可能像这样:
void f(int**);当传递它时,必须取得指针的地址 int**指向指针的指针
int i = 20;
int* p = &i;
f(&p);//OK
对于C++中的引用,语法清晰多了。函数参数变成指针的引用,用不着取得指针的地址。因此:
#include<iostream> using namespace std; void increment(int*& i)//指针的引用 { i++; } int main() { int b = 10;
int* i = &b;
cout<<"i = "<<i<<endl;
cout<<"b = "<<*i<<endl;
increment(i);
cout<<"i = "<<i<<endl;
cout<<"b = "<<*i<<endl;
return 0; }
输出:i = 0012FF44
b = 10
i = 0012FF48
b = 1245064
6、拷贝构造函数
拷贝构造函数,它常被称为X(X&)。在函数调用时,这个构造函数是控制通过传值方式传递和返回用户定义类型的根本所在。事实上,我们将会看到,这是很重要的。