Inside C++ object Model--对象模型概述
在C中, "数据"和"处理数据的操作"是分开声明的, 语言本身并没有支持"数据和函数"之间的关联性. 这种称为"procedural", 由一组算法函数所驱动, 他们处理的是共同的外部数据.
而C++, 则在程序风格, 更在程序的思考上有明显的差异, 它以ADT或class hierarchy的数据封装建立数据和操作的关联性. 在软件工程的眼光来看更为合理.
但是程序员往往出于效率和简易性考虑而选择C.
那么使用C++是否就一定意味着低效了...
其实C++在布局以及存储时间上的额外负担主要是由"virtual"引起的,
-
the virtual function mechanism in its support of an efficient run-time binding, and
-
a virtual base class in its support of a single, shared instance of a base class occurring multiple times within an inheritance hierarchy.
一般而言, 并没有什么天生的理由说C++一定比C庞大或迟缓.
对象模型
作为此书讨论的基础, 首先要来分析一下C++的对象模型. 所谓对象模型, 就是在内存中怎么样来存储一个对象.
对于对象的存储, 下面有3种模型
简单对象模型
这个模型, 顾名思义, 就是为了尽量减低C++编译器的设计复杂度而开发的, 当然简单带来的是空间和执行期的低效.
这个模型中, 对象就是一系列slots, slot中存放了指向members的指针, members按程序中的声明顺序排列.
对象中并不实际存放members, 只是存放member的指针, 这样的好处是member的类型不会影响对象的存储空间.
但是降低了访问效率, 和存储效率, 由于需要通过指针间接访问, 并要额外存储指针.
表格驱动对象模型
这个模型, 相对于简单模型, 更加抽象, 它会把data member和function member分别放在两个table中,
The member function table 和简单模型一样存放的是函数指针. The data member table 直接存放的是data本身.
而对象本身只存放这两个table的指针, 这样最大的好处是, 对象大小是固定的, 无论members怎样改变.
C++对象模型
C++模型从简单对象模型派生而来, 并对内存空间和存取时间做了优化. 各个member的存储方法如下,
Nonstatic data members are allocated directly within each class object.
Static data members are stored outside the individual class object.
Static and nonstatic function members are also hoisted outside the class object.
Virtual functions are supported in two steps:
-
A table of pointers to virtual functions is generated for each class (this is called the virtual table ).
-
A single pointer to the associated virtual table is inserted within each class object (traditionally, this has been called the vptr ).The type_info object associated with each class in support of runtime type identification (RTTI) is also addressed within the virtual table, usually within the table's first slot.
如下图所示, 对于C++对象模型, 对象内只会保存Nonstatic data members和vptr, 这个模型的优点是在于空间和存取时间的效率, 缺点是由于考虑存取效率把Nonstatic data members直接存放在对象中, 导致任何数据成员的改动都会影响类对象的大小. 此处表格驱动对象模型就提供了较大的弹性, 不过鱼和熊掌不能兼得. 在设计时, 就需要根据实际需要进行取舍, C++更看重效率, 而CORBA这样的组件平台, 就会选择耦合度更低的表格驱动模型, 以利于当类成员改变后, 可以不需重新编译客户代码(因为对于这种模型, 对象大小是不变的).
继承的对象模型
前面讨论了基本的C++对象模型, 如果加入了继承语言特性, 对象模型又要做什么样的改动
这个问题就是怎样在内存中存放父类, 派生类, 以及建立之间的关系.
简单的想法就是, 在对象中增加一个slot去存放父类对象指针, 有几个父类就增加几个slots
更透明的方法是, 专门生成一个base class table来存放所有父类指针, 并在对象中增加一个bptr来指向这个table.
这个方法的问题就是由于间接性导致的效率问题, 但优点就是对象对于继承的一致的表现方式, 可以任意修改父类, 而不会影响该类对象本身
前面说了C++更看重效率, 所以它没有采用任何的间接方法,
The data members of the base class subobject are directly stored within the derived class object.
缺点很明显,就是任意base class发生改变, 所有用到该类的派生类都需要重新编译.
关于C++对于虚基类的处理会在后面章节讨论...
![](http://img.zemanta.com/pixy.gif?x-id=14f995ce-1d56-827c-8344-0043983a10c6)