虚函数与虚继承内存分布
注意:虚基指针指向虚基类,虚函数指针指向虚表.
1.1单个继承,不带虚函数
先存基类的内容,再存派生类的内容
1.2单个虚继承,不带虚函数
先存虚基类指针vbptr和派生类内容,再存基类内容
虚继承与继承的区别
// 1. 多了一个虚基指针
// 2. 虚基类子对象位于派生类存储空间的最末尾(先存不变的后存共享的)
2.1单个继承,基类带虚函数,派生类没重写虚函数
先存虚函数指针和基类的内容,再存派生类的内容
2.2单个继承,基类带虚函数,派生类重写虚函数
先存虚函数指针和基类的内容,再存派生类的内容,派生类新增虚函数直接放在基类虚表中
总结:普通继承,派生类新增虚函数直接放在基类虚表中;且基类布局在前面
1.如果派生类没有自己新增的虚函数,此时派生类对象不会产生虚函数指针
2.如果派生类拥有自己新增的虚函数,此时派生类对象就会产生自己本身的虚函数指针(指向新增的虚函数),并且该虚函数指针位于派生类对象存储空间的开始位置
3.1单个虚继承,基类带虚函数,派生类没有重写虚函数
先存虚基类指针vbptr和派生类内容,再存基类的虚函数指针和基类的内容
3.2单个虚继承,基类带虚函数,派生类重写虚函数
先存派生类的虚函数指针,再存虚基类指针vbptr和派生类内容,再存基类的虚函数指针和基类的内容
总结:虚继承多一个虚基指针,如果派生类新增虚函数,则放在最前面;且基类布局放在最后面
4.1普通多重继承,基类都带虚函数,自己有新增虚函数
按照继承顺序来存基类虚函数指针和基类内容,最后存派生类的内容,派生类虚函数会覆盖基类的虚函数,只有第一个虚函数表中存放的是真实的被覆盖的虚函数的地址;其它的虚函数表中存放的并不是真实的对应的虚函数的地址,而只是一条跳转指令
4.2虚拟多重继承,带虚函数,自己有新增虚函数(只有第一个是虚继承)
先存普通继承的虚拟函数指针和基类内容,再存虚基类指针和派生类内容,再存虚基类的虚拟指针和内容.
4.3虚拟多重继承,带虚函数,自己有新增虚函数(三个都是虚继承)
先存派生类的虚函数指针,再存虚基类指针,再存派生类内容,再依次存继承顺序的虚拟指针和基类内容.
// 测试三:多重继承(带虚函数)
// 1、每个基类都有自己的虚函数表
// 2、派生类如果有自己新增的虚函数,会被加入到第一个虚函数表之中
// 3、内存布局中,其基类的布局按照基类被继承时的顺序进行排列
// 4、派生类会覆盖基类的虚函数,只有第一个虚函数表中存放的是真实的被覆盖的虚函数的地址;
// 其它的虚函数表中存放的并不是真实的对应的虚函数的地址,而只是一条跳转指令
5.1菱形普通继承
分解来理解:先存虚拟函数指针和基类,再存派生类的内容.两个基类中先存他们的基类,再存本基类的内容.
5.1菱形虚拟继承
先存父基类的虚拟函数指针和虚基指针和该基内容,再存派生类的内容,再存爷基类的虚拟函数指针和内容.
//虚基指针所指向的虚基表的内容:
// 1. 虚基指针的第一条内容表示的是该虚基指针距离所在的子对象的首地址的偏移
// 2. 虚基指针的第二条内容表示的是该虚基指针距离虚基类子对象的首地址的偏移