首页 > 代码库 > 【C++对象模型】第一章 关于对象
【C++对象模型】第一章 关于对象
1、C/C++区别
C++较之C的最大区别,无疑在于面向对象,C程序中程序性地使用全局数据。而C++采用ADT(abstract data tpye)或class hierarchy的数据封装。类相较于C的struct不仅只包含了数据,同时还包括了对于数据的操作。在语言层面上C++带来了很多面向对象的新特性,类、继承、多态等等。新特性使得C++更加强大,但同时却伴随着空间布局和存取时间的额外成本。这些额外成本主要由 virtual引起,包括:
- virtual function 机制,用来支持“执行期绑定”。
- virtual base class ——虚基类机制,以实现共享虚基类的 subobject。
除此之外C++没有太多理由比C迟缓。
2、C++对象模式
C++中有两种class data members:static、nostatic,以及三种class member functions:static、nonstatic 和virtual。
- nonstatic data members被配置于每一个class object之内;
- static data members则被存在在所有calss object之外;
- static和 non static function members也被放在所有class object之外。
virtual function则以两个步骤支持:
(1)virtual table(vtbl):每个class 产生出一堆指向virtual functions的指针,放在该表格内。
(2)vptr:每个class object 被添加一个指向相关virtual table的指针。vptr的设定和重置都由每个class 的constructor、destructor和copy assignment运算符自动完成。每个class所相关的type_info object(用以支持runtime type identification)也经由virtual table被指出来,通常放在表格第一个slot处。
#include <iostream> using namespace std; class Point { public: Point (float xval); virtual ~Point(); float x() const; static int PointCount(); protected: virtual ostream& print(ostream &os) const; float _x; static int _point_count; };
可以发现,
(1)float _x;被放在class Point之内。
(2)static int _point_count; Point (float xval); float x() const;static int PointCount();不在class Point之内,即放在所有class object外面。
(3)virtual table有两项,表示 virtual ~Point();virtual ostream& print(ostream &os) const;
(4)VS编译器添加了指向相关virtual table的指针vfptr放在class object中,位置在data members的前面。
3、继承
C++继承包括了单一继承、多重继承、虚继承三种继承。
设想一下两种可能的模型:
(1)简单对象模型,derived class object(派生类)内的一个slot指出每一个base class (该slot内含base class subobject的地址)。优点是derived class object的大小不会因base classes的改变而受到影响。缺点是因为间接性而导致空间和存取时间上的额外负担。
(2)base table模型:很像virtual table 内含每一个virtual function的地址,base class table的每一个slot含有一个相关的base class地址。每一个class object内含有一个bptr,被初始化后指向其base class table。
不管采用那种模型,“间接性”的级数都将因为继承的深度而增加。
单一继承、多重继承:
C++最初采用的继承模型并不运用任何间接性:即base class subobject的data members被直接放在derived class object中。这(直接复制模型)提供了对base class 最紧凑而最有效率的存取。缺点是base class members的任何改变后,所有用到此base class或其derived class的objects者必须重新编译。
虚继承:
那么对于C++2.0新加入的virtual base class呢?
需要一些间接性的base class表现方法。其原始模型是在class object中为每一个有关联的virtual base class 加上一个指针。其他演化的模型则若不是导入一个virtual base class table,就是扩充原来已经存在的virtual table,以便维护每一个virtual base class的位置。
总结:
对于单一继承、多重继承采用直接复制模型,对于虚继承则(在直接复制模型的基础上)选择两种间接性模型之一。
那么VS编译器选择哪种继承模型呢?
答案是:virtual base class table模型,具体分析见下一篇)
注:在虚继承的情况下,base class不管在继承串链中被派生多少次,永远只会存在一个实体(subobject)。
4、对象的差异
4.1 编程范式:
C++程序设计模型直接支持三种programming paradigms(编程范式):
(1)程序模型(procedural model):与C一致;
(2)抽象数据类型(abstract data type model,ADT):抽象数据类型是与表示无关的数据类型,是一个数据模型及定义在该模型上的一组运算;其处理的是一个拥有固定而单一的类型的实体,在编译时期就已经完全定义好了。
(3)面向对象模型(object-oriented model):在此模型中有些彼此相关的类型,通过一个抽象的base class(用以提供公共接口)被封装起来。原则上,被指定的object的真实类型在每一个特定执行点之前无法解析。在C++中,只有通过pointer和reference才能够完成。
在需要多态时,对一个base class object,只有通过pointer或reference的间接处理,才支持OO程序设计所需的多态性质。
4.2 C++支持多态的方法:
(1)经由一组隐含的转换操作。
(2)经由virtual function机制。
(3)经由dynamic_cast和typeid运算符。
4.3 多态的主要用途:
经由一个共同的接口来影响类型的封装,这个接口通常被定义在一个抽象的base class中。这个共享接口是以virtual function机制引发的,它可以在执行期根据object的真正类型解析到底是哪一个函数实体被调用。
5、类内存大小计算方法
5.1 一个类的对象的内存大小包括:
- 所有非静态数据成员的大小。
- 由内存对齐而填补的内存大小。
- 为了支持virtual有内部产生的额外负担
如下:
class ZooAnimal { public: ZooAnimal(); virtual ~ZooAnimal(); virtual void rotate(); protected: int loc; String name; };
在32位计算机上所占内存为16字节:int四字节,String8字节(一个表示长度的整形,一个 指向字符串的指针),以及一个指向虚函数表的指针vptr。对于继承类则为基类的内存大小 加上本身数据成员的大小。在cfront中其内存布局如下图:
【C++对象模型】第一章 关于对象