在之前的一篇博文C++中的虚函数表是什么时期建立的?,我们知道虚函数表在编译期间就生成了,但是它被放置在可执行文件的什么地方呢?
为了解决这个问题,我们先来看下C++对象模型。
在C++对象模型中,nonstatic data members被配置于每一个class object中,static data members则被存放在个别的class object之外。static和nonstatic function members也被放在个别的class object之外。virtual functions则以两个步骤支持之:
1. 每一个class产生出一堆指向virtual functions的指针,放在表格之中。这个表格被称为virtual table (vtbl)。
2. 每一个class object被安插一个指针,指向相关的virtual table。通常这个指针被称为vptr。vptr的设定(setting)和重置(resetting)都由每一个class的constructor、destructor和copy assignment运算符自动完成。每一个class所关联的type_info object(用以支持runtime type identification, RTTI)也经由virtual talbe被指出来,通常放在表格的第一个slot。
我们以一个程序来说明C++对象模型:
1 class Point 2 { 3 public: 4 Point(float xval); 5 virtual ~Point(); 6 7 float x() const; 8 static int PointCount(); 9 10 protected: 11 virtual ostream& print(ostream &os) const; 12 float x; 13 static int _point_count; 14 }
其对应的对象模型为:
上图需要注意的一点就是,在大多编译器中,指向虚函数表的指针一般是放在对象的最前边,也就是应该是:
_vptr_Point
float_x
关于C++对象模型,可参考一篇很不错的博文C++对象模型。
另外,从C++的对象模型,我们可以知道一个class object的大小是由以下三点所决定的:
1. 其nonstatic data members的总和大小;
2. 加上任何由于alignment的需求而填补(padding)上去的空间(可能存在于members之间,也可能存在于集合体边界);
3. 加上为了支持virtual而由内部产生的任何额外负担(overhead)。
根据博文关于C++中虚函数表存放位置的思考的分析:
在Linux下,虚函数表存放在可执行文件的只读数据段中(rodata);在Windows下,虚函数表存放在常量段。
参考资料:
《深入探索C++对象模型》