引用
# 1 引用的概念
- 引用可以看作是一个已定义变量的别名。
- 引用没有定义, 是一种关系型声明。声明它和原有某一变量(实体)的关系。故而类型与原类型保持一致, 且不分配内存,与被引用的变量有相同的地址。
- 声明的时候必须初始化, 一经声明, 不可变更。
- 可对引用, 再次引用。多次引用的结果, 是某一变量具有多个别名。
- & 符号前有数据类型时, 是引用,其它皆为取地址.
- 普通引用在声明时必须用其它的变量进行初始化,引用作为函数参数声明时不进行初始化。
- c++中引入引用后,可以用引用解决的问题。避免用指针来解决。
//如果我们在去研究引用的时候,你可以将引用当做一个常指针去研究
//当你在使用引用编程的时候,你就把引用理解为变量的别名就可以了。
1)引用在C++中的内部实现是一个常指针
Type& name <===> Type* const name
2)C++编译器在编译过程中使用常指针作为引用的内部实现,因此引用所占用的空间大小与指针相同。
3)从使用的角度,引用会让人误会其只是一个别名,没有自己的存储空间。这是C++为了实用性而做出的细节隐藏。
# 2 引用作为函数的返回值
# 2.1 当函数返回值为引用时,若返回栈变量: 不能成为其它引用的初始值(不能作为左值使用)
include <iostream>
using namespace std;
int getA1()
{
int a;
a = 10;
return a;
}
int& getA2()
{
int a;
a = 10;
return a;
}
int main(void)
{
int a1 = 0;
int a2 = 0;
//值拷⻉
a1 = getA1();
//将⼀个引⽤赋给⼀个变量,会有拷⻉动作
//理解: 编译器类似做了如下隐藏操作,a2 = *(getA2())
a2 = getA2();
//将⼀个引⽤赋给另⼀个引⽤作为初始值,由于是栈的引⽤,内存⾮法
int &a3 = getA2();
cout <<"a1 = " <<a1<<endl;
cout <<"a2 = " <<a2<<endl;
cout <<"a3 = " <<a3<<endl;
return 0;
}
# 3.2 当函数返回值为引用时, 若返回静态变量或全局变量, 可以成为其他引用的初始值(可作为右值使用,也可作为左值使用)
#include <iostream>
using namespace std;
int getA1()
{
static int a;
a = 10;
return a;
}
int& getA2()
{
static int a;
a = 10;
return a;
}
int main(void)
{
int a1 = 0;
int a2 = 0;
//值拷⻉
a1 = getA1();
//将⼀个引⽤赋给⼀个变量,会有拷⻉动作
//理解: 编译器类似做了如下隐藏操作,a2 = *(getA2())
a2 = getA2();
//将⼀个引⽤赋给另⼀个引⽤作为初始值,由于是静态区域,内存合法
int &a3 = getA2();
cout <<"a1 = " <<a1<<endl;
cout <<"a2 = " <<a2<<endl;
cout <<"a3 = " <<a3<<endl;
return 0;
}
# 3 指针引用
int get_mem2(struct teacher* &tp)
{
tp = (struct teacher*)malloc(sizeof(struct teacher));
if (tp == NULL) {
return -1;
}
tp->id = 300;
strcpy(tp->name, "wang5");
return 0;
}
# 4 const引用
const对象的引用必须是const的,将普通引用绑定到const对象是不合法的。这个原因比较简单,既然对象是const的,表示不能被修改,引用当然也不能修改,必须使用const引用。如下写法是不合法的,编译不过。
const int a=1;
int &b=a;
const引用可使用相关类型的对象(常量,非同类型的变量或表达式)初始化。这个是const引用与普通引用最大的区别。
const int &a=2; //是合法的。
double x=3.14;
const int &b=x; //也是合法
//常引⽤
int x = 20;
const int &y = x; //常引⽤是限制变量通过y去修改x了
//y = 21; //error
# 5 右值引用
以上所述的引用皆为左值引用,左值引用即对左值进行绑定。相应的,右值引用是对右值的绑定。
int&& i = 0;
区分左值和右值:看能不能对表达式取地址,如果能,则为左值,否则为右值。 对右值的引用就是右值引用,而且右值是匿名变量。
T&& k = getVar();//getVar()产生的临时变量不会被销毁,而是会被“续命”,它的生命周期将会通过右值引用得以延续,和变量k的声明周期一样长。
禁止返回值优化,添加参数 -fno-elide-constructors