this指针显式用法以及类对象实际占用内存问题
This指针
This指针的作用域以及作用对象
this作用域是在类内部,而且仅当在类的非静态成员函数中访问类的非静态成员的时候,编译器会自动将对象本身的地址作为一个隐含参数传递给函数。静态成员变量的存储位置在静态存储区,这个存储位置区别于非静态存储区。也就是说,即使你没有写上this指针,编译器在编译的时候也是加上this的,它作为非静态成员函数的隐含形参,对各成员的访问均通过this进行。
This指针的显式用法
当参数与成员变量名相同时,如this->n = n (不能写成n = n),正确代码示例如下:
#include <iostream>
using namespace std;
#include<string>
class Cstudent
{
private:
string name;
int mark;
public:
void ivalue(string name, int mark)
{
this->name = name;
this->mark = mark;
}
void ovalue()
{
cout << this->name << endl;
}
};
int main()
{
Cstudent student;
student.ivalue("超级霸霸强", 89);
student.ovalue();
}
为什么当成员函数形参名称与成员变量一致时,我们在初始化成员函数时必须要写成如上形式,不能写成像下面所表示的那样?
void ivalue(string name, int mark)
{
name = name;
mark = mark;
}
这样是错误的!
我们知道函数体内部的变量使用顺序有优先级,我们把成员函数比作全局变量,函数体内的变量是局部变量,当在函数体内使用name,mark这样与全局变量重名的函数时,系统会默认函数体内使用的name,mark均是函数体内部的局部变量,在函数体内同名变量使用优先级:局部变量>全局变量。
我们可以试一下这个错误示例,它的语法是没问题的,可问题就在于成员变量不会被初始化,而且你还发现不了他——代码错误示例如下:
#include <iostream>
using namespace std;
#include<string>
class Cstudent
{
private:
string name;
int mark;
public:
void ivalue(string name, int mark)
{
name = name;
mark = mark;
}
void ovalue()
{
cout << this->name << endl;
}
};
int main()
{
Cstudent student;
student.ivalue("超级霸霸强", 89); // 使用成员函数简介初始化成员变量
student.ovalue(); // 由于没被正常初始化,所以不会输出任何值
}
用类类型的对象调用成员函数的实质
#include <iostream>
using namespace std;
#include<string>
class Cstudent
{
private:
string name;
int mark;
public:
void ivalue(string name, int mark)
{
this->name = name;
this->mark = mark;
}
void ovalue()
{
cout << this->name << endl;
}
};
int main()
{
Cstudent student;
student.ivalue("超级霸霸强", 89);
// 当你调用这个成员函数时,其实可以拆解为两部分——第一步:student的出现可以把this指针存放的地址指向Cstudent所声明的对象student
// 第二步:用this指针去访问这个成员函数中所有的成员变量,以"this->成员变量名"的形式
student.ovalue();
}
为什么要有this指针,直接在每个对象的存储空间中把数据和函数都存储上不就行了?
这样做是为了节省存储空间提高程序运行效率。我们知道类类型所声明的不同对象只有成员变量的值不同,即不同对象的属性不同。他们所包含的成员函数均相同,即不同对象的行为均相同。相同的东西我们拷贝多份是不是它占用内存。因此编译器采取了如下措施:类类型所声明的对象所占用的存储空间仅是他们的数据部分所占用空间,执行函数则单独存储在另一部分,即不同对象单独使用自己专属的数据部分与共同使用成员函数部分。
那问题又来了:公用的函数体在使用时,如何得知函数体处理的数据是哪个类对象的呢?这就涉及到this指针了,原理如下:
int main()
{
Cstudent student;
student.ivalue("超级霸霸强", 89);
// 当你调用这个成员函数时,其实可以拆解为两部分——第一步:student的出现可以把this指针存放的地址指向Cstudent所声明的对象student
// 第二步:用this指针去访问这个成员函数中所有的成员变量,以"this->成员变量名"的形式
student.ovalue();
}
附加问题:类对象存储所占用的空间是不是就等同于其中基本数据类型所占用空间的累加呢?
其实不是的,稍有偏差。这个涉及到“内存对齐”的问题。我们知道编译器运行必须兼顾存储空间与时间。而且CPU一次访问一个byte的速度是最快的,因此需要采用内存对齐的方式来世的CPU最快的处理,这就使得所占用的存储空间不是最优,但是这样做可以使得整体最优。