📔 Chapter01 关于对象 读书笔记
Chapter01 关于对象¶
对于C来说,数据和函数分开声明,语言本身并不支持 “数据和函数” 之间的关联性。这种程序称为过程性语言。
在C++则是使用独立的 抽象数据结构(ADT)
来实现或者通过一个以二层或者三层的class体系来完成。不管什么方式实现,都可以被参数化。例如实现上述程序转化为C++实现。
通过坐标类型和坐标数目两者都参数化:
1.1 加上封装后的布局成本¶
对于封装后,一般不会增加任何成本。三个data members 直接内含于一个class object中,类似C中struct,而members function 虽然在class 声明中,却不出现在object中。
实际上,类的封装不会带来额外的成本。
C++在布局以及存取时间上主要的额外负担是由 virtual
引起:
virtual function
机制:用来支持一个有效率的 “执行期绑定(runtime binding)
”。virtual base class
:用来实现 “多次实现在继承体系中的 base class”,有一个单一而被共享的实体。
多重继承也会造成额外的负担。
1.2 C++对象模式¶
- 两种class data members:static 和 nonstatic
- 三种class member functions:static、nonstatic 和 virtual。
1.2.1 简单对象模型¶
模型中,一个object是一系列的slots,每个slot指向一个members,Members 按其声明次序,各被指定一个slot,每一个data member 或者function member 都有自己的一个slot。
对于这种索引或者slot数目的概念,被应用在C++中的 “指向成员的指针”概念中。
1.2.2 表格驱动对象模型¶
把所有与members相关的信息抽出来,放在两个table中:
data member table
member function table
class object本身内含这两个表格的指针。data table 直接包含member,func table则包含指针。
1.2.3 C++对象模型¶
Nonstatic data members
存放在class object中
,
static data members
存放到所有的class objetc之外
。static
和 nonstatic function members
则放在所有的class object之外
。virtual function则使用两个步骤来进行支持:
-
每一个class产生一堆指向virtual function 的指针,放在叫作
virtual table(vtbl)
。 -
每一个class object 被添加一个指针,
指向相关的 virtual table
。通常称指针为vptr
。vptr的设定和重置由constructor
,destructor
,copy assignment
运算符自动完成。每个class关联的type_info object
(用来支持RTTI),也经由vitual table被指出来,通常放在表格的第一个slot。
说明:
- RTTI:Runtime Type Identification。
-
优点:
- 空间和存取时间效率提高
-
缺点:
- 如果程序代码本身未改变,但所用到的class object的nonstatic data members发生变化,则需要重新编译代码。
总结:
- 一个vtbl 对应一个class,而一个vptr 对应一个class object。
1.2.4 引入继承后的成本¶
C++支持单一继承,也支持多重继承。而在继承关系中也可以指定为虚拟的(virtual,也有共享的意思)。
在虚拟继承中,base class 不管在继承关串链中被派生了多少次,永远都只会存在一个实体(称为subobject)。
1.3 关键字带来的差异¶
在C所支持的struct 和 C++所支持的class 之间,如果C++使用者,使用自定义类型的格式如下,则可以称为class,但也可以说是struct:
-
C程序员的巧计有时却是C++程序员的陷阱。
如果改用class 来声明,而该class是:
- 指定多个access sections,内含数据。
- 从另一个class 派生而来。
- 定义一个或者多个virtual function。
c++ 中凡是处于同一个access section的数据,必定保证以期声明顺序出现在内存布局中。然而被放置在多个access section中的成员,排列顺序就不一定了。
-
如果需要一个相当复杂的C++ class 的某部分数据,使其有C声明的影子,那么将那部分抽取出来作为一个独立的struct声明。将C与C++组合在一起的做法是:
- 从C struct 中派生出C++的一部分
但是该方式不再推荐使用,因为某些编译器在支持virtual function 机制过程中,对class的继承布局做出了调整。
-
组合:而非继承,才是将C与C++组合在一起的唯一可行方法
- 在组合的情况下,C++ struct 在C++中,当要传递 class object 到某个C函数中时,struct 声明会将数据封装起来,保证拥有与C兼容的空间布局。
- 如果是继承,那么编译器会决定是否有额外data member 安插到base struct subobject 之中。
1.4 对象的差异¶
C++程序设计模型支持是那种程序设计范式
- 过程式模型(procedural model)
- 抽象数据类型模型(Abstract data type model,ADT)
- 面向对象模型(Objec-oriented model)
在C++中,多态
只存在于一个个的 public class
体系中。
Nonpublic 的派生行为
以及类型为 void* 的指针
可以说是多态,但支持性不足,所以严格意义上说,不算是多态。
1.4.1 C++ 支持多态的方式¶
- 经由一组隐含的转化操作
- 经由 virtual function 机制
- 经由 dynamic_cast 和 typeid 运算符
1.4.2 C++ class object的内存大小¶
- 其nonstatic data members 的总和大小
- 加上任何由 alignment(译注)的需求而填补(padding)上去的空间(可能存在于members之间,也可能存在于集合体边界)
- 加上为了支持virtual 而由内部产生的任何额外负担。
一个指针,不管它指向哪一种数据类型,指针本身所需要的内存大小是固定的。
1.4.3 指针的类型¶
“指针类型” 会教导编译器如何解释某个特定地址中的内存内容及其大小。
对于转型(cast),其实就是一种编译器指令,大部分情况下,它并不是改变一个指针所含的真正的地址,只影响“被指出之内存的大小和其内容”的解释方式。
1.4.4 引入多态后¶
编译器在初始化及指定操作(将一个class object 指定给另一个class object)之间做出仲裁,编译器必须确保某个object含有一个或者一个以上的vptr,确保vptrs的内容不会被base class object 初始化或者改变。
对于一个 point
或者一个 reference
来说,之所以支持多态
,是因为并不会引发内存中任何 “与类型有关的内存委托操作
”,但是会受到改变它们所指向的内存的 “大小和内容解释方式
” 的影响。
无论是在 “内存的获得” 或者是 “类型的决断” 上,C++通过 class
的 pointers
和 reference
来支持多态
,这种程序设计风格称为 “面向对象
”。
C++也支持具体的ADT程序风格。