- c++ 继承是如何分配对象空间的?
class Derived:public Base1,private Base2,protected Base3
,在这样的情况下,内存布局与可访问修饰无关,依次放Base1,Base2,Base3,Derived.- c++ 对象中的内存对齐。char无对齐,short默认2字节对齐,int默认4字节对齐,long long默认8字节对齐。默认情况下,32位程序对象首地址,4字节对齐,64位程序对象首地址8字节对齐。当两个char型分配在一起时,只有第一个是对齐的,第二个开始紧挨着放,而当类型不同时,会在中间插入空隙保证对齐性。
__declspec(align(8))
,显式对齐msvc,__attribute__((__aligned__(n)))
,g++. - 当具有虚继承时,
class Derived: virtual public Base1,private Base2,protected Base3
,先放Base2,再放Base3,再放Derived,最后放Base1,注意,Derived头部会有一个虚基指针。
- 虚函数表中的函数是按什么顺序摆放的?
- 首先直接对一个虚函数
&A::virtualfunc
是无法取到其地址的,取出的一个数在不同编译器下有不同表现,不知道其含义,不能用。将class Derived:public Base1,private Base2,protected Base3
中的,如果Base1有虚函数,则Base1的布局开头是一个vfptr
,Base2,Base3
同理,当Derived中重写Base中的虚函数时,Base中将使用被重写的函数的地址,而当Derived中定义新的虚函数时,此时,Derived头部不会生成新的虚函数表,而是将其添加到Base1的虚函数表的后面。在所有的虚函数中,它们一般按定义先后顺序排列,但是虚函数一般放在虚函数表的表头,如果虚函数表是接在基类后边的,那虚函数也是接在后边的位置中的第一个。也就是说,其实虚函数不一定在虚函数表的表头(当它借用Base类的虚函数表的时候)。
总结:
- 内存分布不受
public,private,protected
影响。 - 继承时,先放
class Derived:Base1,Base2,virtual Base3,Base4
,先放不带virtual的Base,再放Derived,最后放virtual Base。即Base>Derived>virtual Base
。 - 虚函数表,虚函数表的优先级高于虚基表,即有虚基表时,虚基表只能跟在虚函数表后面,每个带有虚函数的Base均有一个虚函数表,位于Base分布位置的开头,Derived的虚函数表一般直接加在第一个Base后边(此时,Derived的析构函数就不在表的开头了,而是追加位置的开头)。没有Base带有虚函数时,就在类的内存开头创建一个虚函数表。
- 虚基表,虚基表位于Derived分布的开头,优先级低于虚基表,其表中第一个元素是当前位置相对于表头的偏移,一般是个负值,而后的元素是各个虚基类相对于当Derived的偏移,这是个正值。
提练:
两个优先级: 实父亲>类本身>虚父亲,虚函数表>虚基表
一个借用 :对象本身的虚函数可以跟在其第一个有虚函数实父亲的虚表后面。
顺序 :书写顺序