首页 > 代码库 > 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;

= 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++ 关于引用 &的进一步理解