首页 > 代码库 > c++ 关于引用 &的进一步理解
c++ 关于引用 &的进一步理解
在很久以前看primer的时候看到&有了一些理解,接着在平时使用的时候觉得自己有了更深的理解,发现书上讲得的确挺对但是却不怎么好理解,所以再写一篇来解释一下引用 & 。大神勿喷,有错请指教,本人菜鸟一枚。。。
觉得在学习c++的时候 最重要的一个东西就是,你在学习的时候一定要搞懂它是什么?
那引用是什么呢?
其实呢引用 也是一个指针,哈哈。 为什么呢我们可以看一下
char a = ‘a‘;
char &b = a;
b = ‘b‘;
cout<<b;
代码会输出 字符 b
接着让我们来看一下 sizeof(b) , 你会发现什么 b 居然是四个字节的变量!! 这说明什么?
既能够间接修改 其它变量的值 , 大小又是 四个字节, 这不就是指针, oh shit!
但是一个奇怪的地方是 引用变量 b 必须在初始化的时候赋值,而且还不能改变,这为什么? 没为什么 因为其实它的本质 就是一个 常量指针 char* const b = &a; 可以这样理解, 但是很明显它的表现形式和指针不一样, 这就是c++ 编译器的事情 ,在代码char &b = a; 编译器 隐藏了一些操作, 可以理解成 char* const b = &a; 而在 使用 b 的时候 cout <<b; 编译器又出来干活了 cout<<*b; 真是任劳任怨 啊,,所以我们不妨把引用叫做引用地址,来确定它和地址的关系。
这个大概就是 引用 & 的重点所在了。
那你会问 引用 & 这样做 是为什么?有什么用?
个人的浅见, 1.为了提高程序效率 2.配合c++的对象机制,达到代码易于理解的目的(有多的请补充,错了请指针O(∩_∩)O~)
1.为了提高程序效率,其实这个也就是指针的作用之一
让我们来看这样一个函数
int swap(int &c, int &d)
{
int tmp = 0;
tmp =c;
c = d;
d = tmp;
}
这个函数实现了 a , b 的交换 效果和指针一样
但是在调用的时候却和指针有所不同
只需要
int a = 10;
int b = 20;
swap(a, b);
为什么不用取地址了呢, 我只知道 函数调用的时候实参都是机械的传给形参
就是这样
int &c = a; int &d = b; 然后c++ 编译器帮我们干活
所以得到这样的结果就很明了了吧。
接着还有一个地方 当用引用做函数返回值的时候又怎么理解呢
int& getA()
{
int A = 10;
return A;
}
然后调用该函数
int a;
a = getA();
cout<< a <<endl;
大家都知道这样会乱码,就是a并不是10 而是其他乱起八糟的数(有些环境下不会出错)
想想为什么会这样呢?
为了提高效率 我们都知道 引用类型 就是一个常量指针(返回指针而不返回一个对象或者变量,当然会快一点)而这个指针又指向了一个 A ,A在函数return 的时候就会被释放
指针自然而然的就是一个野指针啦,然后野指针所指向的内存的值又会赋给a,a输出当然会乱码啦。
等等你也许会说 什么指针 ? 在哪里?
我们在开始的时候强调过 引用就是一个 常量指针,,我们可以把它叫做引用指针 , 所以这里的 return A 其实是return A的地址,那怎么取得指针指向内存的值呢 在开始的时候也强调过了 在使用引用地址的时候 编译器会帮我们在指针,前加一个 * 就是读取内存, 而在这个小程序使用引用地址的地方就是 a = getA() ,很明显getA()返回一个引用地址,然后c++编译器在它面前加上*,说到这里你应该明白得差不多了,如果不明白可以留言,或者多用用,多用就懂了。
接下来说第二点
2.配合c++的对象机制,达到代码易于理解的目的
目前一直在学习,用到引用的地方就是在c++的操作符重载上面
主要用到 & 的操作符有 [ ] = >> <<
为什么这几个操作符要用到引用呢 &?
首先将第一个 分析 [ ]
因为 [ ] 有两个作用一个是 读内存 和写内存
比如数组 a[ ]
cout<< a[1] ;就是读内存
a[i] = 1 ; 就是写内存
读内存 很容易 只要访问就可以了
写内存就有一些猫腻了 写内存有一个前提就是得到内存的地址 ,没地址怎么写啊
哈哈,那么重点来了,要用到内存哎,如果用* 的话返回一个地址 但是我们还要手动
的加上 *address 不美观啊, 所以这个时候就是引用出场了
来看这个 操作符的重载
class Array
{
private:
int mLength;
int* mSpace;
public:
Array(int length);
Array(const Array& obj);
~Array();
int getLength();
public:
int& operator[](int i);
Array& operator=(Array &a1);
friend ostream& operator << (ostream& co, Array &obj);
};
int& operator[ ](int i);
int& Array::operator[](int i)
{
return this->mSpace[i];
}
这时我自己写的一个类来看代码, mSpace指向一个动态分配的数组首地址
看上面代码的返回类型 是 int& 是一个引用 说明返回的 this->mSpace[i]的地址
好了再来看看怎么使用
Array b(5);
a[0] = 1;
a[0] 是什么? 看操作符重载函数的返回的类型 很明显 a[0] 是一个地址, 那好这里
就是使用引用类型的地址了, 使用引用类型c++编译器会自动帮我们加上 * 那一切都能解释了
a[ 0 ] 就相当于 *a[ 0 ](如果不想这么看可以这么理解 *address address 就是a[ 0 ] 因为 [ ]已经被重载
不再是原来的读内存的操作了,仅仅是返回数组指定下标元素的地址),所以 给 a[0 ] 赋值 就是给内存块
赋值, 那好第一个解决。
在看看第二 = 号
Array& Array::operator=(Array &obj)
{
if (this->mSpace != 0)
{
delete[] mSpace;
this->mLength = 0;
}
this->mLength = obj.mLength;
this->mSpace = new int[mLength];
int i = 0;
for (i = 0; i < mLength; i++)
{
this->mSpace[i] = obj.mSpace[i];
}
return *this;
}
请忽略 一些不能理解的代码的细节,我们主要讲返回的类型
我们经常使用连等把。
Array a(5);
Array b(5);
Array c(3);
a = b = c;
这里的Array& 引用就是用来解决连等问题的效率。
我们首先来看不连等的情况
a = b;好因为 = 被重载,所以 a 的内存数据,会被改成b的内存数据,但是我们好像忘了说什么,
在重载 [ ] 操作符的时候 a[ 0 ]会返回一个int& 引用, 所以同理,a = b 也会返回一个 Array&
返回的就是 a的地址。然后我们就可以看一看 c = a = b 这时候是什么情况,c = ( a = b)
(a = b) 返回了a的地址, 而我们知道 c++编译器会帮我加 * 好所以其实就是变量 a
即 c = a; 为什么说是 解决效率问题呢,因为如果不是返回Array& 而是Array c++编译器需要
创建一个匿名对象,再把匿名对象的值赋给c 即 c = 匿名对象, 所以返回一个地址,和创建一个
对象,当然是地址的效率快。而且如果我们返回一个Array* 当然也能达到效果,不过我们的代码会
变成 c = *( a = b) 这样的代码看着心痛。
c++ 关于引用 &的进一步理解