这篇文章所使用的方法来源于 CuteQt博客 上的一篇文章:http://www.cuteqt.com/blog/?p=868
生成对象内存布局所使用的方法来自于vc8编译器一个未公开的参数,即 /d1 reportSingleClassLayoutXXX或者 /d1 reportAllClassLayout,MSDN上关于这个的简单说明及示例可以见这里:http://blogs.msdn.com/vcblog/archive/2007/05/17/diagnosing-hidden-odr-violations-in-visual-c-and-fixing-lnk2022.aspx
一般来说用reportSingleClassLayout,因为reportAllClassLayout会生成许多中间类的结果,干扰我们的分析。
按照上面博客中介绍的方法,一步步来跟踪各种虚函数使用情况下的对象内存布局,可以很直观的看到虚函数是怎样分布的,各种继承情况下虚函数是又是怎样生成的,等等。
一点简单的总结:
1。以前常说的,因为虚函数的使用,使得类多了一个vtable指针,大小增加了4字节,其实是不完全正确的。因为一个class内可能会有多个虚表的存在,比如当有多个带虚函数的父类时。
2。多个虚函数在虚表里的顺序由其定义顺序决定。如果是从多个父类派生来的,则这多个虚表的顺序由父类的申明顺序而定。
3。多继承情况下的同名虚函数处理使用了一种叫做thunk的技术,这样通过不同的基类调用同名的虚函数时,都会调用到相同的函数体内。
4。虚基类的实现多了一个vbi表,记录的是虚基类中的虚函数表地址信息。同时在派生类中计算好了到这个vbi表的偏移,这样虚基类里的虚函数在菱形继承关系的派生类中就只有了一份实现。
5。使用的时候其实不必要意这些细节问题,编译器在生成函数调用代码时已经帮我们处理好了,即这个函数在哪个虚表中,是第几个虚函数,最终也就是要做多少个字节的偏移。