零, 这里我们先要澄清一个概念,以免在后面的分析中混淆.
之前我们学习的时候知道:类对象的访问是: 类对象的首地址+偏移量。
这个说法在有多继承的情况下是有问题的。可以参考之前 的 关于 this 指针调整的的一些分析。
CSDNhttps://mp.csdn.net/mp_blog/creation/editor/135737616
由于this指针不一定指向类对象的首地址,因此正确的说法是:
类对象成员的访问是通过: this的地址 + 偏移量
一,单个类带虚函数的数据成员布局(复习)
很显然,由于虚函数的存在,单个 类对象 会多一个vptr指针,这个vptr指针是放在整个数据成员布局的开始位置的,占用4字节(以32位windows 为例说明,实际上是占用1个指针的大小)。
那么显而易见。
class Teacher9 {
public:
int age1;
char ch1;
char ch2;
char ch3;
public:
virtual void func1() {
cout << "Teacher9 virtual void func1 start" << endl;
}
virtual int func2(string str) {
cout << "Teacher9 virtual int func2 start str = " << str << endl;
return 888;
}
};
void main() {
cout<< sizeof(Teacher9) << endl;//12
}
二,子类不带虚函数 继承 父类不带虚函数 数据成员布局(复习)
parent --- son
参考 https://mp.csdn.net/mp_blog/creation/editor/135889041
子类会因为 字节对齐问题 占用空间变大
子类的this对象和父类的this对象都是指向的首地址。
子类内存模型中,会继承父类的私有成员吗? -- 会,但是在子类对象中无法访问父类私有变量
三,子类不带虚函数 继承 父类带虚函数
parent virtual --- son
class Teacher10parent {
public:
int parentage;
private:
int parentprivateage;
public:
void virtual parentfun1() {
cout << "Teacher10parent virtual void parentfun1 start" << endl;
}
};
class Teacher10son :public Teacher10parent {
public:
int sonage;
};
void main() {
cout << sizeof(Teacher10parent) << endl;//12,一个vptr指针 + 两个int
cout << sizeof(Teacher10son) << endl; //16 这说明在子类内存模型中,是会包含父类私有的成员变量的,只是无法访问
}
四,子类带虚函数 继承 父类不带虚函数
parent --- son virtual
//parent -- - son virtual
class Teacher11parent {
public:
Teacher11parent() {
cout << "Teacher11parent 构造函数 this = " << this << endl;
}
public:
int parentage;
private:
int parentprivateage;
public:
};
class Teacher11son :public Teacher11parent {
public:
Teacher11son() {
cout << "Teacher11son 构造函数 this = " << this << endl;
}
int sonage;
public:
virtual void teacher11sonfunc() {
cout << "Teacher11son virtual teacher11sonfunc called" << endl;
}
};
void main() {
cout << sizeof(Teacher11parent) << endl;//8
cout << sizeof(Teacher11son) << endl; //16
//从结果来看,子类和父类的this指针指向是不同的。
//这是因为当子类中 有vptr指针的时候,在内存模型中vptr也会放在父类的前面。
Teacher11son *tson = new Teacher11son;
tson->parentage = 16;
tson->sonage = 18;
long * plong = (long *)tson;
cout << "tson = " << tson << " plong = " << plong << " plong +1 = " << (plong + 1) << endl;
int age = *(plong + 1);
cout << "parenet age = " << age << endl;
Teacher11parent *teap = tson;
cout << "parenet teap = " << teap << endl;
//运行结果为:
// 8
// 16
// Teacher11parent 构造函数 this = 010D5F7C
// Teacher11son 构造函数 this = 010D5F78
// tson = 010D5F78 plong = 010D5F78 plong + 1 = 010D5F7C
// parenet age = 16
// parenet teap = 010D5F7C
printf("Teacher11parent::parentage 偏移量为%p\n", &Teacher11parent::parentage);
printf("Teacher11son::sonage 偏移量为%p\n", &Teacher11son::sonage);
//Teacher11parent::parentage 偏移量为00000000
// Teacher11son::sonage 偏移量为0000000C
}
五 ,子类带虚函数 继承 父类带虚函数
parent virtual --- son virtual
parent 的指针和son 的指针指向的是同一个地址。
//parent virtual -- - son virtual
class Teacher12parent {
public:
Teacher12parent() {
cout << "Teacher12parent 构造函数 this = " << this << endl;
}
public:
int parentage;
private:
int parentprivateage;
public:
virtual void func1(){
}
};
class Teacher12son :public Teacher12parent {
public:
Teacher12son() {
cout << "Teacher12son 构造函数 this = " << this << endl;
}
int sonage;
public:
virtual void teacher12sonvirtualfunc() {
cout << "Teacher11son virtual teacher11sonfunc called" << endl;
}
};
void main() {
cout << sizeof(Teacher12parent) << endl;//12
cout << sizeof(Teacher12son) << endl; //16
Teacher12son *tson = new Teacher12son;
tson->parentage = 9;
tson->sonage = 8;
cout << "duandian " << endl;
}
12
16
Teacher12parent 构造函数 this = 011B5F78
Teacher12son 构造函数 this = 011B5F78
duandian