1.引用
引用并不是定义个新变量,而是给一个变量起一个新的名字,起别名的时候并没有开辟新的空间,而是和原来变量共同使用一块空间;
1.2 引用的定义
类型& 引用变量名(对象名) = 引用实体;
int main()
{
int a = 0;
int& b = a;
}
其实可以这样理解(个人),因为&符号是取地址操作符嘛,int& 类型可以当做a不仅将值赋值给了b,地址也给了b,所以他们共用一块空间。
1.3 引用的特性
1:
因为b是a的别名,使用的是同一块空间,所以b的改变会导致a的改变
void test()
{
int a = 0;
int& b = a;
cout << b << endl;
b = 10;
cout << b << endl;
}
2:
引用的时候必须初始化
3:
引用一旦引用了一个实体就不能被改变
void test()
{
int a = 0;
int& ra = a;
int& rra = a;
}
1.4 引用的权限
1:权限对等和放大
const可以使一个变量的权限缩小(能赋值变成不能赋值),如果我取一个常量的别名会怎么样
void test()
{
int& a = 20;
}
毫无疑问,编译器弹出了一个警告 因为一个常量怎么会有别名呢,如果我加上const呢
void test()
{
const int& a = 20;
}
这时候编译器就没有报错,因为常量本来就不可以修改,那么我加上const后,a也就不能被修改,所以常量也是可以取别名的,但是权限不能放大;
2:权限缩小:
void test()
{
int a = 20;
const int& ra = a;
}
编译器没有报错,说明权限可以缩小
3: 类型转换
void test()
{
int a = 20;
char& ra = a;
int& rra = a;
double& rra = a;
}
但是,如果我加上const
void test()
{
int a = 20;
const char& ra = a;
const int& rra = a;
const double& rra = a;
}
以上编译器都不会报错
这是因为在引用相同类型的时候,是直接将a进行引用,而在进行不同类型的引用时,会产生类型转换,那么会参生一个临时变量原来储存a转换后的值,再将临时变量赋值给ra,在这时如果取直接引用,那么相当于引用了临时变量,而临时变量具有常性(不可修改),所以会报错,那么加上const后就不会报错。
4:总结
以上结果可以说明,引用的权限可以缩小,但是不能放大,并且引用只能引用同之种类型;
1.5 引用做参数和返回值
1:参数
void test(int& a)
{
a = 20;
}
int main()
{
int a = 0;
test(a);
}
形参a就是实参a的别名,改变了形参a就改变了实参a的值,跟传地址的形式是一样的,但是比传地址好用。
但是如果传常量或者是其他类型的数据就会报错
void test(int& a);
void test2(const int& a);
int main()
{
char a;
double b;
test(20);
test(a);
test(b);
test2(20);
test2(a);
test2(b);
}
加上了const就不会报错,道理和上面一样
2:返回值
想想,引用可以作为函数返回值的别名吗
形式一:
int test()
{
int a = 10;
return a;
}
int main()
{
int& a = test();
const int& a = test();
return 0;
}
因为返回a的值时,会使用一个寄存器或者是一个临时变量来存储返回值,待test函数被销毁的时候,a的值就会通过寄存器或者是临时变量来做返回值,所以如果直接引用,那么相对于引用了临时变量或者是寄存器,但是它们都是不可改的,所以要加上const才能做引用;
形式二:
int& test()
{
int b = 10;
return b;
}
int main()
{
int& a = test();
return 0;
}
这其实才是返回值做引用的正确方式,a就是test函数中b的别名,但是还有一些错误,当test函数调用完后空间会被回收,但是a中的地址仍然是test函数中b的地址,但是b的地址已经被系统回收,强行访问会有错误;
形式三:
int& test()
{
static int b = 10;
return b;
}
int main()
{
int& a = test();
return 0;
}
b的值是全局静态变量,所以b的空间不会随着栈帧销毁被回收,这才是正确的使用方式。
因为b是全局的,那么我第一次得到b的别名后,也可以不用接收返回值 例:
int& add(int a,int b)
{
static int ret;
ret = a + b;
return ret;
}
int main()
{
int& a = add(10,20);
cout << a << endl;
add(30, 40);
cout << a << endl;
return 0;
}
结果:
1.6 引用和指针的区别
不同点:
1:引用在定义时没有开辟新的空间,而指针在定义是开辟了空间原来储存地 址 2:引用在定义的时候必须要初始化,而指针不需要 3:有多级指针,但是没有多级引用 4:指针定义后可以被修改,而引用定义后不能被修改 5:访问实体方式不同,指针需要使用解引用操作符访问储存的地址的空间,引用编译器自己处理 6:引用比指针使用起来相对更安全
相同点: 本质是引用和指针是同一个东西,因为引用实现的底层逻辑和指针实现的底层逻辑是一样的,也就是说,其实引用是消耗空间的。
|