this指针调整
首先看代码示例:
#include <iostream>
using namespace std;
class A {
public:
int a;
A()
{
printf("A::A()的this指针是:%p!\n",this);
}
void funA()
{
printf("A::funA()的this指针是:%p!\n",this);
}
virtual void fun()
{
}
};
class B
{
public:
int b;
B()
{
printf("B::B()的this指针是:%p!\n", this);
}
void funB()
{
printf("B::funB()的this指针是:%p!\n", this);
}
};
class C: public A,public B //注意继承顺序,决定了后面的内存布局
{
public:
int c;
C()
{
printf("C::C()的this指针是:%p!\n", this);
}
void funC()
{
printf("C::funC()的this指针是:%p!\n", this);
}
};
int main()
{
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
cout << sizeof(C) << endl;
C myc;
myc.funA();
myc.funB();
myc.funC();
return 0;
}
visual studio2017运行结果:
解释:
(1)A类对象:非静态成员变量a占4个字节,虚函数表指针占4个字节,共8个字节
B类对象:非静态成员变量b占4个字节
C类继承自A类和B类:它的非静态成员变量有 int a; int b; int c;,所以12个字节()
(2)对于子类对象,它是包含父类对象的,会先为其父类对象成员连续分配内存空间,而且分配顺序按照其继承顺序进行,
如上面的例子中先依次连续分配父类对象A,B,子类对象C的内存空间
(3)对于它的父类对象的this也就指向它本身所在内存空间的首地址,而对于子类对象的this它是指向第一个父类对象的首地址,因为整个C对象构成就是它的父类对象+它本身对象,因为(2)中的父类优先连续分配,所以整个子类对象C的首地址也就是父类对象A的内存空间的首地址
所以上面的例子中父类对象A和B的this指针都指向它们各自的内存空间,而子类对象C的this指针指向A的内存空间首地址
图示理解:
修改代码如下:让C类重写父类B中的funB()函数
#include <iostream>
using namespace std;
class A {
public:
int a;
A()
{
printf("A::A()的this指针是:%p!\n",this);
}
void funA()
{
printf("A::funA()的this指针是:%p!\n",this);
}
virtual void fun()
{
}
};
class B
{
public:
int b;
B()
{
printf("B::B()的this指针是:%p!\n", this);
}
void funB()
{
printf("B::funB()的this指针是:%p!\n", this);
}
};
class C: public A,public B //注意继承顺序,决定了后面的内存布局
{
public:
int c;
C()
{
printf("C::C()的this指针是:%p!\n", this);
}
void funC()
{
printf("C::funC()的this指针是:%p!\n", this);
}
void funB()
{
printf("C::funB()的this指针是:%p!\n", this);
}
};
int main()
{
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
cout << sizeof(C) << endl;
C myc;
myc.funA();
myc.funB();
myc.B::funB();
myc.funC();
return 0;
}
结果:
解释:
你调用哪个子类的成员函数,这个this指针就会被编译器自动调整到对象内存布局中 对应该子类对象的起始地址那去;
这里由于在C类中重写了funB(),所以myc.funB()会调用C中的funB,所以此时this指向C对象的起始地址
而在调用myc.B::funB()时,调用的是B中的funB,所以此时this指向B对象的起始地址