说明:
<u>不是很清楚的点</u>,用下划线。
解答,用斜体;
重点,用粗体加粗;
第一章
1.1 C++对象模型
与C语言的Struct相比:
C++使用class封装之后的布局成本没有增加。
- 数据成员直接在类对象内,与Struct的情况一样;
- 成员函数虽然在类中声明,但<u>不在对象(object)中</u>;
- <u>每一个non-inline function 只会产生一个函数实例</u>;
- inline function则会在每一个调用使用的地方产生一个函数实例(在调用点展开函数体);
class在布局以及存取时间上主要的额外负担是由virtual 引起:
- 虚拟函数机制:用以支持一个有效率的“执行期绑定(runtime binding)”;
- 虚拟基类:用以实现“多次出现在继承体系中的 base class ,有一个单一的被共享的实体”;
C++对象模型
在C++对象模型中
非静态数据成员:被放置在每一个class object(对象)之内;
静态数据成员:被存放在所以class object (对象)之外;
静态、非静态函数:都被放在所有 class object 之外;(解答了第一章第一个疑问点)
-
虚函数:
1、每一个 class 产生出一堆指向 virtual functions 的指针,放在表格之中,这个表格被称为 virtual table(vtbl).
2、每一个 class object被添加一个指针,指向相关的virtual table 。通常这个指针被称为 vptr ,vptr的设定和重置都由每一个 class 的 constructor 、destructor 和 copy assignment 运算符自动完成。
加上继承后的C++对象模型(3.4节有讨论)
作者有几种想法,其中一种是下图:
<u>在虚拟继承的情况下,基类(如上图ios类)不管在继承串链中被派生多少次,永远只会存在一个实例。</u>
1.2 关键词所带来的差异
讲关于Struct与Class之间的故事。
1.3 对象的差异
C++支持三种程序设计范式:
程序模型(如C语言);
-
抽象数据类型模型(ADT);
使用的是一个固定而单一的类型的实例,这个实例在编译时期就完全定义好了。
-
面向对象模型(OO)(多态);
只有通过指针或者引用的间接处理,才支持OO程序设计所需的多态性质。因为被指定的object的真实类型在每一个特定执行点之前,是无法解析的。
C++ 以下列方法支持多态:
-
经由一组隐含的转化操作。例如把一个子类指针转换为一个指向其 public基类的指针;
如:
shape *ps = new circle();
经由 virtual function 机制;
经由dynamic_cast和typied运算符;
多态的主要用途是经由一个共同的接口来影响类型的封装,这个接口通常被定义在一个抽象的基类中。这个共享接口是以虚函数机制引发的,它可以在执行期根据object的真正类型解析出到底是哪一个函数实例被调用。
void rotate(X datum, const X *pointer, const X &reference){
//在执行期以前,无法确定到底调用了哪一个rotate实例
(*pointer).rotate();
reference.rotate();
//总是调用datum中的rotate,不管datum中的rotate是否为虚函数
datum.rotate();
}
main(){
Z z; //Z是X的一个子类
rotate(z,&z,z); //pointer和reference的函数调用会被动态完成,在这里都调用Z::rotate()
return 0;
}
一个class object 需要多少内存
- 其非静态数据成员的总和大小;
- 加上任何由于边界调整的需求而填补上去的空间,可能存在于members之间,也可能存在于集合体的边界;
- 加上为了支持 virtual 而由内部产生的任何额外负担,vptr等;
指针类型
一个指向ZoomAnimal的指针是如何与一个指向整数的指针不同?
从内存上看,没有不同!一个指针,不管它指向哪一种数据类型,指针本身所需的内存大小是固定的。
而是,“指针类型”会指导编译器如何解析某个特定地址中的内存内容及其大小。
加上多态以后的指针类型
假设Bear object放在地址1000处,一个Bear指针和一个ZoomAnimal有什么不同?
Bear b;
ZoomAnimal *pz = &b;
Bear *pb = &b;
如图(图中两个指针都是Bear,但可假设其中一个为ZoomAnimal):
它们每一个都指向Bear object的第一个byte。其间的差别是,pb所涵盖的地址包含整个Bear object,而pz所涵盖的地址只包含Bear object中的ZoomAnimal subobject。
Bear b;
ZoomAnimal za = b; //这个引起切割
当一个基类对象被初始化为一个子类对象,那么子类对象就会被切割以塞入较小的base type内存中,多态于是不再呈现。