扫二维码与项目经理沟通
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流
成都创新互联成都网站建设按需定制设计,是成都网站维护公司,为汽车玻璃修复提供网站建设服务,有成熟的网站定制合作流程,提供网站定制设计服务:原型图制作、网站创意设计、前端HTML5制作、后台程序开发等。成都网站营销推广热线:13518219792🥁作者: 华丞臧
📕专栏:【C++】
博主Gitee
各位读者老爷如果觉得博主写的不错,请诸位多多支持(点赞+收藏+关注)。如果有错误的地方,欢迎>在评论区指出。
推荐一款刷题网站 👉LeetCode
引用不是新定义一个变量,而是给已经存在的变量取了一个别名,编译器不会为引用变量开辟内存空间,它们引用的变量共用同一块空间。
//类型& 引用变量名 = 引用实体;
如下:
int a = 10;
int& ra = a; //定义引用类型,必须初始化
二、引用特性void TestRef()
{int a = 10;
// int& ra; // 该条语句编译时会出错
int& ra = a;
int& rra = a;
printf("%p %p %p\n", &a, &ra, &rra);
}
可以看到a,ra,rra三个变量地址一致,从这里可以看出引用其实就是变量实体的别名,与实体共用同一块空间。
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;
}
指针和引用赋值中,变量的权限可以缩小,但不可以放大。
类型转换、整型提升、截断这些的过程中都会产生一个临时变量,语法规定临时变量具有常性即不能修改。
四、使用场景 4.1 做参数在C语言当中,调用一个函数传参分为两种:一是传值二是传地址,在这两种方式中只有传地址才能通过函数中的形参改变实参;而现在C++当中使用引用做形参同样能达到相同的效果。
//这是一个例子
void Swap(int& left, int& right)
{int temp = left;
left = right;
right = temp;
}
引用做参数的优点:
关于函数重载:
int Add(int& a, int& b)
{int c = a + b;
return c;
}
int Add(int a, int b)
{int c = a + b;
return c;
}
上述函数构不构成重载看编译器的识别或者名字修饰规则,但是不能这么写程序会出错,因为调用时存在二义性,编译器识别不出。
传值、传引用效率比较:
#include#includeusing namespace std;
struct A
{int a[10000];
};
void TestFunc1(A a)
{}
void TestFunc2(A& a)
{}
void TestRefAndValue()
{A a;
// 以值作为函数参数
size_t begin1 = clock();
for (size_t i = 0; i< 100000; ++i)
TestFunc1(a);
size_t end1 = clock();
// 以引用作为函数参数
size_t begin2 = clock();
for (size_t i = 0; i< 100000; ++i)
TestFunc2(a);
size_t end2 = clock();
// 分别计算两个函数运行结束后的时间
cout<< "TestFunc1(A)-time:"<< end1 - begin1<< endl;
cout<< "TestFunc2(A&)-time:"<< end2 - begin2<< endl;
}
int main()
{TestRefAndValue();
return 0;
}
可以看到,数据量很大的时候引用做参数的效率更快。
传值返回:
我们知道在函数调用时,编译器会为函数在内存中开辟一个函数栈帧;在函数调用返回时函数栈帧销毁之前,返回值会先传给一个临时变量(小则存放在寄存器中,大则在主函数栈帧开辟的空间)返回。
引用返回:
引用是什么?引用是一个变量的别名,和引用的实体是共用一块空间的;那么在函数栈帧销毁时,函数返回的是实体变量在这个过程中就不会再产生一个临时变量。
注意:函数栈帧销毁,该函数中的局部变量也销毁了,这时就不能再用引用返回了;如果这个变量是定义在函数栈帧上的,函数栈帧销毁变量也跟着销毁,出了函数作用域返回变量不存在了,不能使用引用返回,因为此时引用返回的结果是未定义的;出了函数作用域,返回变量存在,才能使用引用返回。
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);
Add(3, 4);
cout<< "Add(1, 2) is :"<< ret<
打印一次:
打印两次:
说明:
- 打印一次的时候,add函数栈帧销毁时函数栈帧中存放c变量的空间并没有被销毁改变,此时去访问这块空间的值还是7。
- 当第二次打印两次的时候,我们第二次非法访问同样一块空间发现值已经被改变,这是因为先取值再打印所以第一次还是7但是此时
cout
函数调用开辟了栈帧覆盖了那片空间,从而导致了值的改变。- 上述的那一段程序是错误,属于非法访问,这说明:出了函数作用域变量就不存在了是不能使用传引用返回的。
引用返回的优点:
值和引用的作为返回值类型的性能比较:
#include#includeusing namespace std;
struct A
{int a[10000];
};
A a;
// 传值返回
A TestFunc1()
{return a;
}
// 引用返回
A& TestFunc2()
{return a;
}
void TestReturnByRefOrValue()
{// 以值作为函数的返回值类型
size_t begin1 = clock();
for (size_t i = 0; i< 100000; ++i)
TestFunc1();
size_t end1 = clock();
// 以引用作为函数的返回值类型
size_t begin2 = clock();
for (size_t i = 0; i< 100000; ++i)
TestFunc2();
size_t end2 = clock();
// 计算两个函数运算完成之后的时间
cout<< "TestFunc1 time:"<< end1 - begin1<< endl;
cout<< "TestFunc2 time:"<< end2 - begin2<< endl;
}
int main()
{TestReturnByRefOrValue();
return 0;
}
通过上述代码的比较,发现传值和传引用在作为传参以及返回值类型上效率相差很大。
在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间;但在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。
int main()
{int a = 10;
int& ra = a;
ra = 20;
int* pa = &a;
*pa = 20;
return 0;
}
上述引用和指针的汇编代码如下:
通过对比不难发现,引用的底层是使用指针实现的。
引用和指针的不同点
:
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧
我们在微信上24小时期待你的声音
解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流