本篇文章将带你了解C++引用。引用作为C++新设计的类型,其功能与指针有所交集,在一定程度上代替了一些指针的用法,而希望本篇文章能令你引用的理解有帮助。
根据C++Primer上的解释,引用是一种复合类型,通过在变量名前添加“&”符号来定义。复合类型是指用其他类型定义的类型。在引用的情况下,每一种引用类型都“关联到”某一其他类型。不能定义引用类型的引用,但可以定义任何其他类型的引用。
通俗地讲,引用不是定义一个新的变量,而是给已存在变量取一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。此外,引用类型与实体类型必须是同种类型
引用代码演示:
void demo1()
{
int a = 10;
int& ra = a;//定义引用类型变量
printf("%d\n", a);
printf("%d\n", ra);//使用上当作变量a使用
}
void demo2()
{
int a = 3;
int b = 5;
//int& ra; //这句代码编译会出错
//error C2530: “ra”: 必须初始化引用
int& ra1 = a;
int& ra2 = a;
int& ra3 = ra1;
ra1 = b;//这句只是赋值
//两个不相同的地址
cout << &ra2 << endl;
cout << &b << endl;
cout << ra1 << endl;
cout << ra2++ << endl;
cout << ra3++ << endl;
cout << a << endl;
}
常引用,或者说const
引用,是指向const
对象的引用。注意,const
本质是赋予修饰的变量(对象)常属性,也就是说const
引用是对具有常属性的实体的引用。
代码演示:
void demo3()
{
const int a = 3;
//int& ra = a;// a是具有常属性的变量
// error C2440: “初始化”: 无法从“const int”转换为“int &”
const int& ra = a;
//int& rb = 10;// 10是常量
// error C2440: “初始化”: 无法从“int”转换为“int &”
const int& rb = 10;
double c = 3.1415;
//int& rc = c;// 引用类型与实体类型不相同
// error C2440: “初始化”: 无法从“double”转换为“int &”
const int& rc = c;
//本质上rc引用的是强制类型转换时产生的临时变量,
//此临时变量是不能被修改的,具有常属性
}
int& Count1()//1
{
static int n = 0;
//...
return n;
}
做返回值
int& Count2()//2 wrong
{
int n = 0;
//...
return n;
}
//想想为什么Count2的写法是错误的
//
// 对于Count1来说,由static修饰的n的数据存放于静态区,出了函数生命周期时并不会释放该空间
//
// 对于Count2来说,变量n的数据只是存在与Count2函数栈帧中,
// 出了函数生命周期时,这一整块函数栈帧都会被释放
//
// 这就意味着这块空间随时都有可能被访问或者修改
//
// 所以,使用int&作为返回值时,对于返回的数据必须不是出了函数栈帧2就销毁的数据
// 例如全局变量,static修饰的数据,malloc申请出来的数据
//
以上的事情,对于C语言来说,使用指针也能实现,当然,引用相较于指针的使用必然是比较便利的,那么C++设计出的引用相比于指针仅仅就只有这一点优势吗?答案自然不是,毕竟语言设计者们可都是真正的大佬呀。
首先,以值作为参数或者返回值类型,在传参和返回期间,函数并不会直接传递实参或者将变量本身直接返回,而是在传递实参或返回变量的一份临时拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率会更加低下。
#include<time.h>
typedef struct A
{
int n[100000];
}A;
A a;
A test1()
{
return a;
}
A& test2()
{
return a;
}
void demo5()
{
//直接以值为返回值类型
size_t begin1 = clock();
for (int i = 0; i < 10000; i++)
test1();
size_t end1 = clock();
//以引用为返回值类型
size_t begin2 = clock();
for (int i = 0; i < 10000; i++)
test2();
size_t end2 = clock();
cout << "test1 time: " << end1 - begin1 << "ms" << endl;
cout << "test2 time: " << end2 - begin2 << "ms" << endl;
}
不同于指针,在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。
但引用在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。
在以下引用和指针操作的实现中,转到反汇编看汇编指令时,你会发现使用的汇编指令是一样的。
(但是实际使用中并不需要你去关心这一点)
void demo6()
{
int a = 1;
int& ra = a;
ra = 2;
int* pa = &a;
*pa = 1;
}
总结:
sizeof
中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)。以上就是C++的引用详解,引用作为C++新设计的类型,最初的设计意图也是为了解决C指针使用的一些不便和痛点,所以引用类型还是非常好用的。最后,非常感谢读者朋友们能够读完本篇文章。不知这种短小的文章读起来体验如何,我在尽可能精简文章,让读者能按需索取,不浪费时间。如果你觉得做的还不错的话请点赞收藏加分享,当然如果发现我写的有错误或者有建议给我的话欢迎在评论区或者私信告诉我。