要点提纲:
1、对象模型
对象模型主要是讲了数据成员和函数在对象中的分布。
- 对于类来说,主要的数据成员分为 static 和 non static, 成员函数分为 static、non static 、virtual。
- 主要介绍了三类对象模型:
1、简单对象模型
2、表格驱动对象模型
3、c++对象模型 –> 实际使用模型 - 类对象内存大小的计算
1、nonstatic data members的总和大小
2、内存对齐
3、为支持virtual机制而产生的内存。
2、class和struct的区别——其实没啥区别
3、多态的实现,虚函数机制的讲解
- p25 c++支持多态的三种方式
1、基类指针或引用 指向派生类
2、虚函数
3、RTTI(runtime type identification):dynamic_cast 和typeid运算符 - 指针或引用 与 对象的差别
- 同时指出了一个很关键的实现,指针和引用的类型决定了编译器如何去解析指针或引用所对应的空间。
1、C++在布局以及存取时间上的额外负担是由virtual引起
此处是指C++中虚函数以及虚继承机制,虚函数是C++中实现多态的主要手段,虚继承则是为了解决诸如菱形继承中:爷爷以上类在孙子以下类中出现多份重复数据,造成数据冗余、歧义和命名冲突提出的,详细的内容在后面的章节中由介绍,之后的笔记会再详细做整理。
2、C++对象模型(The C++ Object Model)
在C++中,有两种class data members(类数据成员):static(静态数据)和nonstatic(非静态数据),以及三种class member functions(类成员函数):static(静态函数)、nonstatic(非静态函数)和virtual(虚函数)。已知下面这个class Point声明:
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;
};
这个class Point在机器中将会被怎么样表现呢?即:我们如何模塑(modeling)出各种data members和function members呢?
a. 简单对象模型(A Simple Object Model):
这个模型十分简单,可能是为了尽量降低C++编译器的设计复杂度而开发出来的,却赔上了空间和执行期的效率。
一个object(对象)是一系列的slots(位置、槽),每一个slot指向一个member(成员)。Members按其声明顺序,各被制定一个slot。每一个 data member(数据成员) 或 function member(成员函数)都有自己的slot。
在这个简单模型中,所有实际的members(成员)不存储在object(对象)本身的空间中,只有“指向member的指针”才放在object内。这是为了避免“members有不同的类型,因而需要不同的存储空间”所招致的问题。Object中的members是以slot的索引值来寻址的,本例中的 _x 的索引是6,_point_count的索引是7。
因此:一个class object的大小很容易计算出来:“指针大小,乘以class中所声明的members个数”便是。
虽然这个模型并没有被应用到实际产品上,但“索引”、“slot个数”的观念却被应用到了C++的“指向成员的指针”(pointer-to-member)观念之中。
b. 表格驱动对象模型(A Table-driven Object Model):
为了对所有类(class)的所有对象(object)都有一致的表达式,表驱动对象模型把所有与“成员(member)”相关的信息抽取出来,放在一个“数据成员表(data member table)”和一个“成员函数表(member function table)”,而类对象(class object)中则含有指向这两个table的指针,例如:
c. C++对象模型(The C++ Object Model):
C++对象模型将静态数据成员、静态成员函数和一般非静态成员函数均存放在个别的class object之外(单独存取,和对象无关),而非静态数据成员则被放在每一个class object内,虚函数则以下面两个步骤支持:
- 每一个class产生一堆指向虚函数的指针,并且按照顺序置于虚函数表(virtual table,vtbl)。
- 每一个class object被安插一个指针(vptr),指向相关的virtual table。vptr的**设定(setting)以及重置(resetting)**都由每一个class的constructor, destructor和copy assignment运算符自动完成(由于构造函数来设定vptr,故构造函数无法设置为虚函数 具体可参考《后台开发核心技术P59》的笔记)。每一个class 所关联的type_info object(用于支持RTTI)也通常放在虚函数表的第一个slot。