前言:

        由于经常使用C++,但是又对C++内部机制不是很深入了解,所以看了一些关于C++的经典书籍,其中有《C++ Primer》、《STL源码剖析》、《Efficitive C++》、《More Efficitive C++》。《C++ Primer》特别适合刚使用C++的程序员学习,里面详细介绍了一些C++基础知识,包括流和STL容器、适配器、算法还有C++的面向对象的一些知识。这里主要介绍一些我看《深入探索C++对象模型》的一些理解。

        对于面向对象(Object Oriented)语言,我们的疑惑就很多了。究其原因,这中语言的编译器为我们(程序员)做了很多我们不知道的服务:构造函数、析构函数、虚拟函数、继承、多态.......有时候它会为我们生成一些额外的函数,又有时候它会扩张我们所写函数的内容,放进更多的操作,还有时候它会为我们的object添油加醋,放一些奇妙的东西,使我们面对sizeof的结果大惊失色。

    本书《深入探索C++对象模型》分为七章。

第1章,关于对象,提供以对象为基础的观念背景,以及由C++提供的面向对象程序设计典范。主要是对于对象模型的一个大略浏览,说明目前普及的工业产品,但没有对多重继承和虚拟继承有太靠近的观察。

第2章,构造语意学,介绍构造函数,构造函数何时被编译器合成,以及给程序带来的效率问题。

第3章,Data语意学,主要专注于各式各样的data member,详细介绍了data member的处理。

第4章,Function语意学,主要专注于各式各样的member functions,详细介绍了vitual functions。

第5章,构造、析构、拷贝语意学,讨论了如何支持class模型,也讨论了object的生命周期。

第6章,执行期语意学,检视执行期的某些对象模型行为,包括临时对象的生命机器死亡,以及对new运算符和delete运算符的支持。

第7章,在对象模型的尖端,专注于exception handling、template support、runtime type indentification。

1、什么是对象模型

(1)语言中直接支持面向对象程序设计的部分

(2)对于各种支持的底层实现机制

        C与C++的区别,C语言中是将“数据”和“处理数据的操作(函数)”分离开来的,语言本身没有支持“数据和函数”之间的关联性,但是在C++中,却提供了一种ADT,它将“数据”和“ 处理数据的操作(函数)”结合起来,加入了class关键字。

        考虑C++加上封装之后是否会产生布局成本,答案是:否!实际上,在C++中class就像C的struct的情况一样,member functions虽然含在class声明之内,却不出现在object之中,每一个non_inline member function只会诞生一个函数实体。至于每一个“拥有零个或一个定义”的inline function则会在其每一个使用者身上产生一个函数实体。这一个并未带给它任何空间或执行期的不良回应。C++在布局以及存取时间上主要的额外负担是由vitual引起,包括:vir1function机制、vitrtual base class。

2、C++对象模式

        在C++中,有两种class data member:static和nonstatic,以及三种class member functions:static、nonstatic和virtual。C++对象模型有三种:(1)简单对象模型(A Simple Object Model)

                                                                  图1 简单对象模型

        在简单模型中,members本身并不放在object之中。只有“指向member的指针”采放在object内。这么做可以避免“member有不同的类型,因而需要不同的存储空间”所招致的问题。但是这个模型并没有并运用与实际产品上,不过关于索引或solt数目的观念,倒是被运用到C++的“指向成员的指针”(Pointer-to-member)观念之中。

         表格驱动对象模型(A Table-driven Object Model):为了对所有class的所有objects都有一致的表达方式,表格对象模型是将所有与members相关的信息抽出来,放在一个data member table和一个member function table之中,class object本身则内含指向这两个表格的指针。Member function table是一系列的solts,每一个solt指出一个member function;Data member table则直接含有data本身。               

                                                        图2 表格对象驱动模型

    表格对象驱动模型也没有实际运用于真正的C++编译器上,但member function table这个观念却成为支持visual functions的一个有效方案。

        C++对象模型:可以说C++对象模型是继承了简单对象模型和表格驱动模型的两者的优点。它是从简单对象模型派生而来的,并对内存空间和存取时间做了优化。在模型中,Nonstatic data member被配置于每一个class object之内,static data member则被存放在所有的class object之外,static和Nonstatic function members也被放在所有的class object之外。Visual functions则以两个步骤支持之:

(1)每一个class产生一堆指向visual functions的指针,放在表格之中。这个表格称为visual table(vtbl)。(这种思想是从表格驱动模型中继承而来的)。

(2)每一个class object被添加了一个指针,指向相关的visual table(虚函数表)。通常这个指针称为vptr。vptr的设定和充值均由每一个class的constructor,destructor和copy assignment运算符自动完成。每一个class所关联的type_info object也经由visual table指出来,通常放在表格的第一个solt处。    

                                                                    图3 C++对象模型

        这个模型主要优点在于它的空间和存取时间的效率;主要缺点:如果运用程序代码未曾改变,单所用的class objects的nonstatic data members有所修改,那么那些运用程序均得重新编译,关于这一个点,前面的双表格模型可以提供较大的弹性,但因为多提供了一层间接性,因此也付出了执行空间和效率两方面的代价。

3、C++继承

(1)单一继承

(2)多重继承

(3)虚拟继承

虚拟继承特点:base class不管在继承串链中派生多少次,永远只会有一个实体。

        “简单对象模型”中,每一个base class可以被derived class object内的每一个solt指出,该solt内含base class object的地址。这种机制的主要缺点:间接性导致空间和存取时间上的额外负担,优点则是class object的大小不会因其base class的改变而受影响。

        “base table模型”也就是表格驱动模型中,base class table被产生出来时,表格中的每一个solt内含一个相关的base class地址。主要缺点:由于间接性而导致空间和存取时间上的额外负担,优点则是在每一个class object中对于继承都有一致的表现方式:每一个class object都应该在某个固定的位置上安放一个base table指针,与base classes的大小或数目无关,第二个优点,不需要改变class object本身,就可以放大、缩小、或更改base class table。

4、struct与class区别

        思想上的区别:struct关键词的使用实现的是C的数据萃取观念,而class关键词实现的是C++的ADT观念。C++原本不是必须需要class关键字,但是它的加入,体现了C++的封装和继承的哲学。

        内存存放的区别:struct是按声明顺序来存放数据,故可以使用小技巧来实现一个可变大小的数组,但是C++中class内数据存储却不一定是与声明一致,如:base classes和derived classes的data members的布局并没有强制规定谁先谁后。

        默认权限的却别:class默认权限为private,而struct的默认权限是public。

5、 对象的差异

        C++程序设计模型直接支持三种programming paradigms(程序设计典范)。

(1)程序模型(procedural model):面向过程,如字符串处理,可以使用字符数组以及str*函数集。

(2)抽象数据类型模型(ADT):该模型所谓的“抽象”是和一组表达式(public接口)一起提供,而其运算定义隐而未明。如:string class。

(3)面向对象模型(object-oriented model):类和继承、多态等。其中C++有三种方法支持多态:1)经由一组隐含的转化操作。例如把一个derived class指针转化为一个指向其public base class指针。

2)经由visual function机制

3)经由dynamic_cast和typeid运算符。

6、多态机制

        指针:指针的内存大小固定,在32位机器上占4个字节,在64位机器上占8个字节。转型(cast)(如:ZooAnimal  *px)其实是一种编译器指令。大部分情况下它并不会去真正影响一个指针的地址,它只影响“被指出之内存的大小和内容”的解释方式。

        多态允许继一个抽象的public接口之后,封装相关的类型。所付出的代价就是额外的间接性——不论是在“内存的获得”或是在“类型的决断”上,C++通过class的pointers和references来支持多态,这种程序设计风格就称为“面向对象”。

结论:

        C++哲学思想:面向对象,其中:封装、继承、多态是核心,为了实现封装引入class关键字,然后详细介绍了class和struct的区别,还介绍了C++对象模型,C++的多态机制,内存分配等。

参考文献:

[1] 侯捷 《深入探索C++对象模型》


Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐