深度探索C++对象模型总结
C++对象模型主要解释为:
- 语言中直接支持面向对象程序设计的部分
- 对于各种支持的底层实现机制
关于对象
C语言中,数据和处理数据的操作时分开声明,而C++采用抽象数据类型进行操作。在C++加上封装并未带来布局成本,在布局以及存取时间上主要的额外负担是由virtual引起的:
- virtual function 机制:用以支持一个有效率的“执行期绑定”。
- virtual base blass : 用以实现“多次出现在继承体系中的base class, 有一个单一而被共享的实例”。
- 多重继承下的一些额外负担。
C++对象模型
- 简单对象模型:members本身不放在objects中,object存储指向member的指针。
- 表格驱动对象模型:数据与操作分离为两个表格,object存储指向两个表格的指针。
- C++对象模型:每一个class产生一堆指向virtual functions的指针,放在virtual table(vtbl)中,每一个class object安插一个vptr指向相关的virtual table,每一个class关联的type_info objects信息。vptr的设定和重置都由每一个class的constructor, destructor, copy assignment自动完成。
关键词所带来的差异
当一个人感觉到比较好的时候,使用struct取代class,注意struct在C++中的逻辑意义和如何正确使用。
对象的差异
C++程序设计模型直接支持三种程序设计范式:
- 程序模型
- 抽象数据类型模型
- 面向对象模型
纯粹以一种范式编写程序,有助于整体行为的良好稳固。
C++以下列方式支持多态:
- 经由一组隐式的转化操作,例如把derived class指针转化为一个指向其public bass type的指针
- 经由virtual function
- 经由dynamic_cast和typeid运算符
多态的主要用途是经由一个共同的接口来影响类型的封装。
需要多少内存才能够表示一个class object:
- 其nonstatic data members的总和大小
- 任何alignment的需要而填补的空间
- 为了支持virtual 而由内部产生的任何额外负担
构造函数语意学
Default Constructor的构造操作
default constructors在需要的时候被编译器产生出来,但需要注意的是这种需要时编译器方面的而不是程序的需要。一个由于为声明constructor函数而被隐式声明的default constructor将是一个trivial(无用) constructor,在某些情况编译器将会生成nontrivial default constructor.
- 带有Defulat Constructor 的Member Class Object:
在constructor真正被调用生成,编译器在包含这样member的constructor中自动扩张,将member的constructor行为先进行
运行,其调用顺序根据member objects在class中的声明顺序决定。 - 带有Default Constructor 的Base Class
与上面同理,bass class的constructor先进行调用。 - 带有一个Virtual Function的Class
class声明或者继承一个virtual Function / class派生自一个继承链,其中有一个或多个virtual base classes.
一个virtual function table 会被编译器生成,内放virtual function地址。vptr内含vtbl的地址。 - 带有Virtual Base Class 的 Class
Copy Constructor的构造操作
有三种情况使得一个object的内容作为另一个class object的初值:
- 对一个object做显示的初始化操作
- 当object被当做参数交给某个函数时
- 当函数传回一个class object时
Default Memberwise Initialization:为定义一个explicit copy constructor时,将object使用递归方式拷贝每个成员。
当class不展现Bitwise Copy Semantics时会合成copy constructor:
- 当class内含一个声明有copy constructorh的member object
- 继承的base class有一个copy constructor(不论是显示声明还是合成而得)
- 当class声明一个多多个virtual functions
- 当class派生于继承链,其中有一个或多个virtual base classes
程序转化语意学
成员们的初始化队伍
- 初始化一个reference member
- 初始化一个const member
- 调用一个base class的constructor,而他拥有一组参数
- 调用一个member class的constructor, 而它有一组参数
initialization list的初始化会被以适当的顺序在constructor之内安插初始化操作,并且在任何explicit user code之前。
Data 语意学
- 语言本身所造成的额外负担
- 编译器对于特殊情况所提供的优化处理
- Alignment限制
Data Member的绑定
一个inline函数实体,在整个class声明未被完全看见之前,是不会被评估求值得。
Data Member的布局
static data merbers不会被放进class的布局中,members的顺序根据编译器而定,较晚出现的members有较高的地址。
Data Member的存取
- Static Data Members
static 成员只有一个实例,通过一个指针和对象存取member结果一样。若取一个static data member的地址会得到一个指向
其数据类型的指针。name-mangling对其进行独一性的编码。 - Nonstatic Data Members
在成员函数内,data members通过隐式的this指针进行访问,不同data数据的访问是通过对class object地址进行偏移进行访问。
Data members的地址在编译期即可获得,当使用继承之类的机制,data members的存取效率会受到影响。
继承与Data Member
具体继承并不会增加空间或者存取时间的额外负担。但加上多态机制之后情况就会有所不同,vtbl 和vptr的创建,constructor和destructor对
vtbl和vptr的设定和销毁都会带来空间和时间上的负担。
将vptr放在class object的尾端可以保留base class C struct的对象布局。将vptr放在class object的前端对于在多重继承下,通过指向class
members的指针调用virtual function带来一些帮助。
多重继承
虚继承
对象成员的效率
指向Data Members的指针
取一个nonstatic data member的地址,将会得到它在class中的offset
Function 语意学
Member的各种调用方式
Nonstatic Member functions
- 改写函数的signature以安插一个额外参数(this)到member function以提供存取管道,使得class object得以将此函数调用。
- 将每一个“对nonstatic data member”的存取操作改为经由this指针来存取。
- 将member function通过mangling重新写成一个独一无二的·外部函数。
Virtual Member functions
通过虚运行机制进行调用。
Static Member functions
- 没有this指针
- 不能直接存取class中的nonstatic members
- 不能够被声明为const, volatile, virtual
- 不需要经由class object才被调用
- 取一个这样的地址将获得其内存中的地址吗,是一个nonmember函数指针。
Virtual Member functions
多态以一个public base class的指针或引用寻址出一个derived class object。每个多态class object增加两个members
一个字符串或数据表示class的类型和一个指向某个表格的指针(vptr),为了找到函数地址,每一个virtual function被指派一个表格
索引值。
多重继承下得Virtual functions
函数的效能
指向Member Function的指针
取一个nonstatic member function的地址得到的时它在内存中真正的地址,这个值不是完全的,需要被绑定到某个class object上才能
够通过它调用该函数。
Inline Functions
- 分析函数定义
- 真正的inline函数扩展操作是在调用的那一点上。
构造,析构,拷贝语意学
纯虚函数的存在:可以定义和静态调用一个pure virtual Function, pure virtual function一定需要进行定义,派生类需要进行相关调用。
“无继承”情况下得对象构造
Plain OI Data :struct
抽象数据类型 :ADT(Class)
带virtual function类 :constructor需要再任何base class construtors调用之后,在任何使用者供应的代码之前进行附加vptr初始化。
这个时候,copy constructor和copy assignment operator不再是trivial,同样需要对vptr进行操作。
继承体系下得对象构造
- 虚继承:解决virtual base class的共享性问题
vptr初始化语意学
- 当一个完整的对象被构造起来时
- 当一个subobject constructor调用了一个virtual function
对象复制语意
对象的效能
析构语意学
- 如果object内含一个vptrm那么首先重设相关的virtual table
- destructor的函数本体现在被执行
- class拥有member class objects,而后者有destructors,那么它们会以声明顺序的相反顺序被调用
–
执行期语意学
对象的构造和析构
将object尽可能放置在使用它的那个程序区段附近,这样做可以节省非必要的对象产生操作和摧毁操作。
- 全局对象: 需要静态初始化
- 局部静态对象: 初始化一次
- 对象数组:
new和delete运算符
- 通过设当的new运算符函数实例,配置所需的内存
- 将配置得来的对象设立初值