this指针
我们先来看一个下面的例子
在这个例子中,我们定义了一个Array数组的类,并且只定义了一个数据成员len,同时定义了三个成员函数:一个是Array类的有參的构造函数,将传入的_len赋值给其数据成员len,还有两个数据成员len的封装函数(getLen和setLen)。通过观察,大家是不是发现参数与数据成员均不重名(比如我们这里的数据成员是len,但是所有的传入参数都是_len)。大家回想一下,在此前的代码中,是不是也都是这种情况?是不是也都是数据成员与它的参数在表达同一个意思的时候用的是不同的名字,这也是当时我们故意这样做的。为什么这样做呢,这是为了顺利完成前面知识的讲解。但是,大家当时是不是都注意到这个问题呢?是否考虑过,如果传入的参数与数据成员重名会怎样呢?下面我们就来一探究竟。还是看一个例子,如下:
我们看到在这个例子当中,传入的参数与其数据成员重名了。那么,重名之后,我们发现有两个问题:一个是其构造函数中,一个是setLen()封装函数中,无论是我们还是计算机无法判断究竟是将传入的参数赋值给其数据成员了,还是将其数据成员赋值给传入的参数了。既然计算机无法判断,就会把这样的一种赋值认为是错误的。可见在这个例子中,我们遇到的主要问题呢,就是编译器无法分辨哪个是作为参数的len,哪个又是作为数据成员的len。这就是说,我们迫切需要一种技术,这种技术要么可以标记出参数,要么可以标记出数据成员,那么这种技术就是我们这里所要讲到的this指针。
this指针是什么呢?
this指针就是指向其自身数据的指针。
我们一起来看一下,在刚才的例子中,如果我们实例化一个arr1对象,那么this指针就相当于给arr1取地址,也就是说this就是arr1的地址;如果我们继续实例化一个对象arr2,那么this指针此时就是arr2的地址。我们画一个示意图如下所示:
可见,通过this指针就可以访问到它表达的对象的自身的任何数据。比如说,当this是arr1的地址的时候,就可以访问到arr1的数据成员len及其他数据成员;如果this表达的是arr2的地址的时候,也就可以访问到arr2的数据成员len及其他数据成员。这从另一个角度来说,就可以标记处它自身的数据成员,应用到代码当中呢,我们可以写成这样:
我们可以看到,如果我们用与数据成员重名的参数,那么我们就可以在数据成员的前面用this加指针符号来表达数据成员的len,然后将参数的len赋值给数据成员的len。这样计算机就不会疑惑究竟是传入的参数赋值给其数据成员了,还是将其数据成员赋值给传入的参数了,从而就可以正常的编译了,进而我们也可以使用与数据成员重名的参数来进行表达了。下面我们回到之前我们没有使用this指针的例子来继续观察。
通过观察,我们还发现了什么呢?难道大家没有对成员函数中直接去访问数据成员这种做法产生过怀疑吗?好吧,我们还是先来回顾一下,此前所学的一些知识吧。
这是一个汽车的类,在这个汽车的类中,我们有一个数据成员,这个数据成员就是指这个汽车的轮子的个数,当然,还定义了一个成员函数。当时我们给大家讲的时候,是讲的这些数据成员以及它的成员函数究竟是放在内存中的什么位置的。回顾一下,如上面有图所示,如果我们实例化了一个car1对象,那么car1就拥有了自己的数据成员(轮子的个数 wheelCount),同理我们又实例化了一个car2和car3,那么car2和car3也就拥有了自己的数据成员(轮子的个数wheelCount),但是呢,它的成员函数却只有一份,这份成员函数是写在代码区的,如果car1这个对象,car2这个对象,car3这个对象分别去调用成员函数的时候,那么car1,car2和car3都可以去访问代码区中的这个成员函数,而访问的时候也不会出任何的问题,在成员函数被调用当中呢,也各自调用了各自的数据成员,并且也没有出现混乱。
那么讲到这里,大家是不是发现了什么呢?既然函数的逻辑代码都是以二进制的方式存储在代码区中,参数中也没有数据成员,那么在调用数据成员的时候怎么可能成功呢?更重要的是,当存在多个对象时,函数又如何确定该调用哪个对象的数据成员呢?要解决这个问题,也归功于this指针,我们继续来看下面这个例子。
这个例子非常奇怪,我们仔细的看一下。对比之前的例子,是不是每一个成员函数的参数列表中都多出了一个this指针,那么有了这样一个this指针,刚刚前面所提到的一系列问题也就迎刃而解了。