深入探索C++对象模型-第一章

说明:

​ <u>不是很清楚的点</u>,用下划线。

解答,用斜体;

重点,用粗体加粗;

第一章

1.1 C++对象模型

与C语言的Struct相比:

C++使用class封装之后的布局成本没有增加

  1. 数据成员直接在类对象内,与Struct的情况一样;
  2. 成员函数虽然在类中声明,但<u>不在对象(object)中</u>;
  3. <u>每一个non-inline function 只会产生一个函数实例</u>;
  4. inline function则会在每一个调用使用的地方产生一个函数实例(在调用点展开函数体);

class在布局以及存取时间上主要的额外负担是由virtual 引起:

  1. 虚拟函数机制:用以支持一个有效率的“执行期绑定(runtime binding)”;
  2. 虚拟基类:用以实现“多次出现在继承体系中的 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 运算符自动完成。

1-3.png

加上继承后的C++对象模型(3.4节有讨论)

作者有几种想法,其中一种是下图:

1-4.png

​ <u>在虚拟继承的情况下,基类(如上图ios类)不管在继承串链中被派生多少次,永远只会存在一个实例。</u>

1.2 关键词所带来的差异

讲关于Struct与Class之间的故事。

1.3 对象的差异

C++支持三种程序设计范式:

  • 程序模型(如C语言);

  • 抽象数据类型模型(ADT);

    ​ 使用的是一个固定而单一的类型的实例,这个实例在编译时期就完全定义好了。

  • 面向对象模型(OO)(多态);

    ​ 只有通过指针或者引用的间接处理,才支持OO程序设计所需的多态性质。因为被指定的object的真实类型在每一个特定执行点之前,是无法解析的。

C++ 以下列方法支持多态:

  1. 经由一组隐含的转化操作。例如把一个子类指针转换为一个指向其 public基类的指针

    如:shape *ps = new circle();

  2. 经由 virtual function 机制;

  3. 经由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 需要多少内存

  1. 非静态数据成员的总和大小;
  2. 加上任何由于边界调整的需求而填补上去的空间,可能存在于members之间,也可能存在于集合体的边界;
  3. 加上为了支持 virtual 而由内部产生的任何额外负担,vptr等;

指针类型

​ 一个指向ZoomAnimal的指针是如何与一个指向整数的指针不同?

​ 从内存上看,没有不同!一个指针,不管它指向哪一种数据类型,指针本身所需的内存大小是固定的。

而是,“指针类型”会指导编译器如何解析某个特定地址中的内存内容及其大小。

加上多态以后的指针类型

​ 假设Bear object放在地址1000处,一个Bear指针和一个ZoomAnimal有什么不同?

Bear b;
ZoomAnimal *pz = &b;
Bear *pb = &b;

​ 如图(图中两个指针都是Bear,但可假设其中一个为ZoomAnimal):

1-5.png

​ 它们每一个都指向Bear object的第一个byte。其间的差别是,pb所涵盖的地址包含整个Bear object,而pz所涵盖的地址只包含Bear object中的ZoomAnimal subobject。

    Bear b;
    ZoomAnimal za = b;      //这个引起切割

​ 当一个基类对象被初始化为一个子类对象,那么子类对象就会被切割以塞入较小的base type内存中,多态于是不再呈现。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容