文章目录
- 1、引用概念
- 2、引用特性
- 3、常引用
- 4、引用的使用场景
- (1)做参数
- (2)做返回值
1、引用概念
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。
类型& 引用变量名(对象名) =引用实体;
注意:引用类型必须和引用实体是同种类型的
void TestRef()
{
int a = 10;
int& ra = a;//<====定义引用类型
printf("%p\n", &a);
printf("%p\n", &ra);
}
//两者地址一致
2、引用特性
引用在定义时必须初始化
一个变量可以有多个引用
引用一旦引用一个实体,再不能引用其他实体
void TestRef()
{
int a = 10;
// int& ra; // 该条语句编译时会出错,因为它未初始化
int& ra = a;
int& rra = a;
printf("%p %p %p\n", &a, &ra, &rra);
}
3、常引用
意思就是const类型的引用也要const,不能const int 使用int引用。
void TestConstRef()
{
const int a = 10;
//int& ra = a; // 该语句编译时会出错,a为常量
const int& ra = a;
// int& b = 10; // 该语句编译时会出错,b为常量
const int& b = 10;
double d = 12.34;
//int& rd = d; // 该语句编译时会出错,类型不同
const int& rd = d;
}
int Count()
{
int n = 0;
n++;
return n;
}
int main()
{
int a = 1;
int& b = a;
// 指针和引用,赋值/初始化 权限可以缩小,但是不能放大
// 权限放大
/*const int c = 2;
int& d = c;
const int* p1 = NULL;
int* p2 = p1;*/
// 权限保持
const int c = 2;
const int& d = c;
const int* p1 = NULL;
const int* p2 = p1;
// 权限缩小
int x = 1;
const int& y = x;
int* p3 = NULL;
const int* p4 = p3;
// 权限只适用于指针和引用,这个是可以的,n和m两个空间是独立的
//const int m = 1;
//int n = m;
const int& ret = Count();//n是临时变量传值返回,不可被修改,加个const才行
//这部分听不懂,以后遇到重新学习
int i = 10;
cout << (double)i << endl;
double dd = i;
const double& rd = i;
return 0;
}
4、引用的使用场景
(1)做参数
void Swap(int& left, int& right)
{
int temp = left;
left = right;
right = temp;
}
//使用了引用,函数里面改的就是实参,不需要用到取地址再解引用
函数在使用引用时,函数参数是引用int& i,实参也可以使i,因为他们是不同作用域的,可以同名。
形参的改变影响实参。 比如**phead的运用。
(2)做返回值
count 函数调用时,n的返回过程。
第一种是没有static,count的函数栈帧结束后,n的值传给临时变量,这个临时变量是在寄存器或者main函数里面开辟的,此时count函数栈帧被销毁还给操作系统,临时变量再赋值给main函数中的ret。
第二种是有static,其实和第一种差不多,只不过n是放在静态区,n一样要赋值给临时变量。
第三种是传引用返回,直接返回n,而不是传给临时变量。
int& Count()
{
static int n = 0;
n++;
// ...
return n;
}
下面代码输出什么结果?为什么?
int& Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int& ret = Add(1, 2);//这里的&去掉,ret依然是c的别名,函数结束后c依然还给了操作系统,ret一定是未知,当然有可能对,取决于第一次栈帧销毁时c的值。
Add(3, 4);
cout << "Add(1, 2) is :"<< ret <<endl;//7
return 0;
}
//上面是c是局部变量,函数结束后还给了操作系统,此时ret是c的引用别名,所以ret的值是未知的。
注意:如果函数返回时,出了函数作用域,如果返回对象还在()引用返回,如果已经还给系统了,则必须使用传值返回。