这一节我们研究的是 this指针
那么C++中类成员函数是如何知道哪个对象调用了它?并正确显示调用它的对象的数据呢?
Teacher tea;
Teacher tea2;
tea.func();
tea2.func();
当x.func()时候,func函数怎么知道是tea调用的?还是tea2调用的?换句话说:怎么知道x的地址是tea还是tea2?
实际上当一个对象x调用func的时候,会隐式的将自己的地址传进去,这个隐式的参数就是this指针,this指针中存放的就是这个对象的首地址。
当一个对象调用某成员函数时会隐式传入一个参数, 这个参数就是this指针。this指针中存放的就是这个对象的首地址。
这和C中通过向函数传递结构体变量的地址是不是很像?只是传参形式不一样罢了! 在C中我们是手工把结构体变量和函数关联起来的,而C++则是编译器帮我们把类数据和成员函数关联起来的并通过名称粉碎和编译时检查等形式防止外部的任意访问。
那么这个this指针存放在哪里呢?
其实编译器在生成程序时加入了获取对象首地址的相关代码。并把获取的首地址存放在了寄存器ECX中(VC++编译器是放在ECX中,其它编译器有可能不同)。也就是成员函数的其它参数正常都是存放在栈中。而this指针参数则是存放在寄存器中。
类的静态成员函数因为没有this指针这个参数,所以类的静态成员函数也就无法调用类的非静态成员变量。
当一个子类继承一个父类。子类对象的this指针和父类对象的this指针对比。
class Teacher4 {
public:
Teacher4() {
cout << "Teacher4::Teacher()的this 指针是 " << this << endl;
}
void func4() {
cout << "Teacher4::func4()的this 指针是 " << this << endl;
}
int mage4;
};
class Teacher6 :public Teacher4 {
public:
Teacher6() {
cout << "Teacher6::Teacher()的this 指针是 " << this << endl;
}
void func6() {
cout << "Teacher6::func6()的this 指针是 " << this << endl;
}
int mage6;
};
void main() {
cout << sizeof(Teacher4) << endl; //4
cout << sizeof(Teacher6) << endl; //8
Teacher4 tea4;//Teacher4::Teacher()的this 指针是 00000019BCCFF7E4
Teacher6 tea6;//Teacher4::Teacher()的this 指针是 00000019BCCFF808 Teacher6::Teacher()的this 指针是 00000019BCCFF808
cout << sizeof(tea4) << endl; //4
cout << sizeof(tea6) << endl; //8
cout << " &tea4 = " << &tea4 << endl;//&tea4 = 00000019BCCFF7E4
cout << " &tea6 = " << &tea6 << endl; //&tea6 = 00000019BCCFF808
tea4.func4(); //Teacher4::func4()的this 指针是 00000019BCCFF7E4
tea6.func4(); //Teacher4::func4()的this 指针是 00000019BCCFF808
tea6.func6(); //Teacher6::func6()的this 指针是 00000019BCCFF808
//从上面看到,&tea4 和 &tea6 中 this 指针是同一个。
}
从结果上看:子类用的this指针,实际上是父类的this指针
当子类继承了多个父类,那么子类对象中的this指针是那个父类的呢?
this指针调整:多存在于多重继承的情况下。
class Teacher7 {
public:
Teacher7() {
cout << "Teacher7::Teacher()的this 指针是 " << this << endl;
}
void func7() {
cout << "Teacher7::func7()的this 指针是 " << this << endl;
}
int mage7;
};
class Teacher8 {
public:
Teacher8() {
cout << "Teacher8::Teacher()的this 指针是 " << this << endl;
}
void func8() {
cout << "Teacher8::func8()的this 指针是 " << this << endl;
}
int mage8;
};
class Teacher9 :public Teacher7, public Teacher8{
public:
Teacher9() {
cout << "Teacher9::Teacher()的this 指针是 " << this << endl;
}
void func9() {
cout << "Teacher9::func9()的this 指针是 " << this << endl;
}
int mage9;
};
//多继承时用的是那个this指针
void main() {
Teacher7 tea7;//Teacher7::Teacher()的this 指针是 000000C93E54FCB4
cout << "&tea7 = " << &tea7 << endl;//&tea7 = 000000C93E54FCB4
Teacher8 tea8;//Teacher8::Teacher()的this 指针是 000000C93E54FCD4
cout << "&tea8 = " << &tea8 << endl; //&tea8 = 000000C93E54FCD4
Teacher9 tea9;
// Teacher7::Teacher()的this 指针是 000000C93E54FCF8
// Teacher8::Teacher()的this 指针是 000000C93E54FCFC
// Teacher9::Teacher()的this 指针是 000000C93E54FCF8,说明子类中的this 用的是 第一个继承的父类
cout << "&tea9 = " << &tea9 << endl;//&tea9 = 000000C93E54FCF8
tea7.func7(); //Teacher7::func7()的this 指针是 000000C93E54FCB4
tea8.func8();// Teacher8::func8()的this 指针是 000000C93E54FCD4
tea9.func7();//Teacher7::func7()的this 指针是 000000C93E54FCF8
tea9.func8();//Teacher8::func8()的this 指针是 000000C93E54FCFC
tea9.func9();//Teacher9::func9()的this 指针是 000000C93E54FCF8
//如果换成class Teacher9 :public Teacher8, public Teacher7 那么tea9的this对象就是父类的tea8的
}
结论:
A,如果派生类只从一个基类继承,那么派生类对象的起始地址和基类对象的起始地址是一样的。
B ,如果派生类从多个基类继承,那么派生类对象的起始地址 和 继承的第一个 基类对象的地址相同,后面这些基类对象的开始地址和派生类对象的开始地址相差多少呢?那就要把前面的基类对象锁占用的空间内存减掉。
C ,this就是对象的起始地址,假设 TeacherC,继承了TeacherA,继承了TeacherB,那么teac.func();this指针是和teaa的this指针是同一个。当调用teac.funb()的时候,this指针就会发生变化,这时候this指针和teab的this指针是同一个。这就叫做 this指针调整
D,this就是对象的起始地址,假设 TeacherC,继承了TeacherB,继承了TeacherA,那么teac.func();this指针是和teab的this指针是同一个。当调用teac.funa()的时候,this指针就会发生变化,这时候this指针和teaa的this指针是同一个。这就叫做 this指针调整