本科毕业之后有时间重新系统学习一遍C++,因此决定写一系列笔记帮助自己理解,也许也能提供新的思路给和我一样的老萌新小萌新。
要理解引用,那么就要先理解C++的精华之指针,引用和指针是密不可分的,我们甚至可以说这俩就是一个东西。但是指针能做的事情比引用更多,而引用的出现简化了C++代码,毕竟指针可是凭借一己之力抬高了C++入门门槛,估计大家看见代码里满篇的指针都会虎躯一震吧~~
从指针开始
那么指针是什么?
指针只是一个地址,不要多想,这真的很简单!
不要考虑数据类型,对于任意数据来说,指针只是一串存储内存地址的数字。不论是什么数据类型,其地址所代表的长度是固定的,因为这主要取决于当前系统的框架。比如说,x86系统寻址为4个字节,那么代表地址的那一串儿数字就是4个字节的。在x86框架下,一个int类型的地址和double类型和char类型的地址都是4字节。
int main(){
int a = 5;
void* ptr_i = &a;
double b = 123.4;
void* ptr_d = &b;
return 0;
}

在debug模式下查看内存,可以看到同为4字节(0x表示这是16进制显示,后面每一位都可以写成0-F,也就是16位数,也就是242^424,也就是4个bit. 1个字节有8bit,因此2位数代表1个字节,一共8位数,所以是4字节)
数据类型的重要性体现在对内存的操作
通过上述操作,已经完成了对数据类型的取地址操作,也就是可以获取某个数据的内存地址了。那么,如果想要通过内存地址反向对该数据进行操作,就需要提前通知编译器该地址指向的数据的数据类型。
#include<iostream>
#define LOG(x) std::cout << x << std::endl;
int main(){
int a = 5;
int* ptr = &a;
*ptr = 6;
LOG(a);
return 0;
}

至此,我们掌握了如何通过指针改变地址指向的数据。
讲到引用
简单理解引用,就是一个变量的别名。那么既然是别名,在引用前就必须存在一个“本名”,因此引用不可为空。
int main(){
int a = 5;
int& ref = a;
return 0;
}
通过引用改变数据的方法
int main(){
int a = 5;
int& ref = a;
ref = 6;
LOG(a);
return 0;
}

至此,我们掌握了引用的基本用法。
自增函数的例子
void Increment(int x){
x++
}
int main(){
int a = 5;
Increment(a);
return 0;
}
由于x是局部变量,自增只会发生在Increment函数当中(在函数当中创建一个新的变量等于a的值,而后对该变量进行操作),不会影响a的值,因此a在这一系列操作之后依旧还是5.
如果希望a本身发生变化,那么使用指针的方法如下:
void Increment(int* x){
(*x) ++; //先找到x位置对应的数据,再自增
}
int main(){
int a = 5;
Increment(&a);
LOG(a);
return 0;
}

看着已经有点混乱了是不是,引用的出现极大地简化了代码,请看:
void Increment(int& x){
x ++; //不用再找指针,有时候甚至用指针还是引用傻傻分不清
}
int main(){
int a = 5;
Increment(a); //不用写取地址
return 0;
}

如此清爽的代码,完成了和之前指针一样的工作。谁能不爱引用呢?
但是指针为什么还存在?
强大的指针
int main(){
int a = 5;
int b = 6;
int& ref = a;
ref = b;
return 0;
}
上述代码原本的核心任务是,更改引用,也就是从引用a更新为引用b. 然而我们明白ref = b 只是将ref指向的变量赋值为b,而无法重新引用。这也是引用重要的一个性质:只可以引用一次。
但是指针就没有这样的限制,它可以指向任意的同数据类型的数据。
int main(){
int a = 5;
int b = 6;
int* ptr = &a;
*ptr = 3;
ptr = &b;
*ptr = 4;
return 0;
}

由此可见,指针在必要时候还是非常有用的。
-1
2281

被折叠的 条评论
为什么被折叠?



