引用的本质
在C++中,引用使用&修饰,相当于给变量取别名,有两个特点:1)引用必须初始化。2)引用初始化之后就不能更改。下面这两条语句都是错的:
int &a;
int &a=10;
正确的写法如下:
int b=10;
int &a=b;
这样a与b就相当于是同一块内存上数据的名称(别名)。本质上,引用是一个指针常量,即:
int &a=b;
等价于:
int * const a =&b;
这也解释了为什么引用不能更改,因为const限定了指针的指向不能变。在使用引用时,我们可以像使用普通变量一样赋值操作,编译器会完成解引用和取地址操作。
返回引用的函数
函数的返回值可以是引用,但是不要返回局部变量的引用,因为局部变量在栈上,函数结束后自动释放,而上面讲了,引用的本质是指针常量,那么再使用引用来访问该局部变量会产生乱码(编译器可能会保留一次使用,但第二次使用时就会变成乱码)。
那么如何正确返回引用呢,将返回变量放在全局区或者堆区就可以了,下面写两个函数演示一下:
int& test01(){
static int a=10;
return a;
}
int& test02(){
int* a=new int(10);
return *a;
}
void main(){
int&c=test01();
int&d=test02();
cout<<c<<" "<<d<<endl;
}
运行之后输出的结果不出意外应该是:10 10
返回引用的函数作为等号的左值
在上面的例子中,把main函数里的代码改一下:
void main(){
int&c=test01();
int&d=test02();
cout<<c<<" "<<d<<endl;
test01()=100;
test02()=1000;
cout<<c<<" "<<d<<endl;
}
不出意外的话,结果应该是;
可以发现,函数返回引用时可以作为等号左值,相当于给返回的引用所指向的变量赋值,但是在全局区和堆区操作的结果不一致,之所以会这样是因为new这个关键字会在堆区开辟新的内存返回给引用,而static存储在全局区,不会开辟新内存,所以c所指向的内存会因为赋值发生改变,而d所指向的内存并不会发生赋值操作,因为test02()=1000;操作的是new开辟的一块新内存。
可以在函数中输出地址验证一下,将上述两个函数改成:
int& test01() {
static int a = 10;
cout << (int)(&a) << endl;
return a;
}
int& test02() {
int* a = new int(10);
cout << (int)(a) << endl;
return *a;
}
void main(){
int&c=test01();
int&d=test02();
cout<<c<<" "<<d<<endl;
test01()=100;
test02()=1000;
cout<<c<<" "<<d<<endl;
}
那么运行main函数的输出变成:
全局区的地址一样,堆区的地址变了。